3진법 뒤집기

나의 기록·2026년 7월 8일

코딩테스트

목록 보기
25/35

https://school.programmers.co.kr/learn/courses/30/lessons/68935#

자연수 n을 3진법으로 바꾼 뒤, 자릿수를 앞뒤로 뒤집고, 다시 10진법으로 표현한 값을 구하는 문제.

  • n = 45 → 3진법 "1200" → 뒤집으면 "0021" → 10진법 7
  • n = 125 → 3진법 "11122" → 뒤집으면 "22111" → 10진법 229

1차 시도: 억지로 예외처리

10진수를 3으로 나눈 나머지를 계속 뽑으면, 그 순서 자체가 이미 "뒤집힌" 자릿수라는 점까지는 파악했다. 문제는 반복문 종료 조건이었다.

while(n/3>=1){
    sb.append(n%3);
    if(n/3==1){
        sb.append(n/3);
    }
    n=n/3;
}

n/3>=1, 즉 n>=3일 때만 반복하도록 짜서 마지막 자릿수(가장 큰 자릿값)가 통째로 안 잡혔다. 이걸 억지로 메꾸려고 n/3==1일 때만 따로 하나 더 append 하는 예외처리를 넣었는데, 이게 45와 125 두 예제에서는 우연히 답이 맞아버렸다 (두 수 모두 3진법 최상위 자리가 마침 1이었음).

반례로 버그 확인

주어진 예제만 믿지 않고 직접 다른 값을 대입해서 확인하는 과정이 필요했다. n=8(3진법 "22")을 손으로 트레이싱해보니:

  • 최상위 자리가 1이 아니라 2인 경우, if(n/3==1) 조건에 아예 걸리지 않음
  • 결과적으로 최상위 자릿수가 통째로 유실됨

→ "예제 두 개가 맞는다"와 "코드가 맞다"는 다르다는 걸 확인한 케이스.

수정: 종료 조건 자체를 바꾸기

특정 자리만 잡아내는 예외처리 대신, 반복문이 끝나는 시점 자체를 바로잡았다.

while(n>=1){
    sb.append(n%3);
    n=n/3;
}

n이 0이 될 때까지, 즉 더 이상 나눌 게 없을 때까지 돌리면 모든 자릿수가 빠짐없이 처리된다. 예외 케이스를 패치하는 대신 애초에 예외가 생기지 않는 조건으로 바꾼 것.

10진법 변환

뒤집힌 자릿수 배열을 순회하면서 각 자리의 위치값(3의 거듭제곱)을 직접 계산해서 곱해 더하는 방식으로 처리했다.

for(int i=0; i<a.length; i++){
    int cnt = 1;
    long exp=1;
    while((a.length-1)-i>=cnt){
        exp*=3;
        cnt++;
    }
    answer += exp * Integer.valueOf(a[i]);
}

동작은 맞지만, 자바에 3진법 문자열 ↔ 10진수 변환을 지원하는 메서드가 있다는 걸 알게 됨 (Integer.toString(n, 3), Integer.parseInt(s, 3)). 다음엔 이걸로 더 짧게 짤 수 있을 듯.


배운 점

  • 주어진 예제 통과 ≠ 정답: 예외처리로 예제를 억지로 맞추면, 그 예외처리가 커버 못 하는 반례가 항상 있다. 반복 조건 자체를 점검해야 함.
  • 반복문 종료 조건: "특정 값일 때 하나 더 처리" 식의 패치보다, 애초에 마지막 케이스까지 자연스럽게 포함하는 종료 조건(n>=1 / n>0)을 찾는 게 더 견고함.
  • 나머지의 주기성: n을 1씩 늘리며 m으로 나눈 나머지는 0~m-1을 주기 m으로 순환함 (나머지가 가질 수 있는 값이 m개뿐이라서). 이번 문제처럼 나머지를 반복 추출하는 로직을 짤 때 이 성질을 이해하고 있으면 종료 조건을 헷갈리지 않는 데 도움이 됨.
profile
뭐든 남겨본다

0개의 댓글