https://school.programmers.co.kr/learn/courses/30/lessons/68935#
자연수 n을 3진법으로 바꾼 뒤, 자릿수를 앞뒤로 뒤집고, 다시 10진법으로 표현한 값을 구하는 문제.
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")을 손으로 트레이싱해보니:
if(n/3==1) 조건에 아예 걸리지 않음→ "예제 두 개가 맞는다"와 "코드가 맞다"는 다르다는 걸 확인한 케이스.
특정 자리만 잡아내는 예외처리 대신, 반복문이 끝나는 시점 자체를 바로잡았다.
while(n>=1){
sb.append(n%3);
n=n/3;
}
n이 0이 될 때까지, 즉 더 이상 나눌 게 없을 때까지 돌리면 모든 자릿수가 빠짐없이 처리된다. 예외 케이스를 패치하는 대신 애초에 예외가 생기지 않는 조건으로 바꾼 것.
뒤집힌 자릿수 배열을 순회하면서 각 자리의 위치값(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)을 찾는 게 더 견고함.