프로그래머스 Lv2. 124 나라의 숫자 (Java / Python)

eora21·2022년 9월 2일
0

프로그래머스

목록 보기
9/38

문제 링크

문제 간단 해석

1, 2, 4로 모든 수를 표현하는 방법.
'숫자가 3개이니 3진법 쓰면 되지 않나?' 라는 생각에서 파생한다면 쉽게 풀 수 있다.
Java로는 3진법으로 값을 구한 뒤 변환하는 방법을, Python으로는 해당 방법을 3진법으로 변환하는 와중 쉽게 값을 뽑는 방법을 소개하겠다.

Java

3진법 수행 후 값을 변환.

풀이 코드

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Collectors;

class Solution {
    public String solution(int n) {
        List<Integer> list = new ArrayList<>();
        int val;
        
        while (n != 0) {
            list.add(n % 3);
            n /= 3;
        }
        
        for (int i = 0; i < list.size() - 1; i++) {
            val = list.get(i);
            
            if (val <= 0) {
                list.set(i+1, list.get(i+1) - 1);
                list.set(i, val + 3);
            }
        }
        
        if (list.get(list.size() - 1) == 0)
            list.remove(list.size() - 1);
        
        Collections.reverse(list);
        
        return list.stream()
            .map(v -> Integer.toString(v))
            .collect(Collectors.joining(""))
            .replace("3", "4");
    }
}

해석

List<Integer> list = new ArrayList<>();
int val;

3진법 값들을 담을 List와 값을 담을 val 선언.

while (n != 0) {
    list.add(n % 3);
    n /= 3;
}

n을 3진법으로 변환하여 담는다.
이 때, 순서는 우리가 원하는 방식과 거꾸로임에 주의.

for (int i = 0; i < list.size() - 1; i++) {
    val = list.get(i);

    if (val <= 0) {
        list.set(i+1, list.get(i+1) - 1);
        list.set(i, val + 3);
    }
}

값을 확인하며 0이 있는지 찾는다.

3진법과 답을 비교할 시, 0이 있다면 해당하는 앞자리에 -1을 수행하고 4가 들어가게 된다.
이처럼 0이 발견된다면 앞자리에서 -1을 한 후 현재 위치에 +3을 수행했다(계산의 편의를 위해 4 대신 3을 넣는 방식, 밑에서 3을 4로 변환할 것이다).

if (list.get(list.size() - 1) == 0)
    list.remove(list.size() - 1);
    
Collections.reverse(list);

현재 list 내의 값들은 순서가 뒤집혀져 있다. 즉, 맨 뒷자리가 맨 앞자리로 오게 된다.
혹여나 맨 앞자리로 올 수가 0이라면, 출력하지 않도록 미리 제거했다.
그 후 reverse로 순서를 맞춰줬다.

return list.stream()
    .map(v -> Integer.toString(v))
    .collect(Collectors.joining(""))
    .replace("3", "4");

현재 list의 내부 값은 int 형태이므로, map을 통해 String으로 변환한다.
그 후 join을 통해 하나의 문자열로 만든 후, 아까 계산의 편의를 위해 3으로 넣어줬던 값을 4로 변환하여 return한다.

Python

3진법을 사용하되 더 나은 규칙을 찾아 풀이

풀이 코드

def solution(n):
    answer = 0
    i = 1
    
    while n:
        val = n % 3
        
        if val == 0:
            answer += 4 * i
            n -= 1
        else:
            answer += val * i
            
        n //= 3
        i *= 10
    
    return str(answer)

해석

answer = 0
i = 1

값을 담을 answer와 현재 자릿수인 i를 선언.

while n:
    val = n % 3
    
    if val == 0:
        answer += 4 * i
        n -= 1
    else:
        answer += val * i
        
    n //= 3
    i *= 10

마찬가지로 n % 3을 통해 3진법의 수를 구한다.
이 때, 현재 구해진 값이 0이라면 값은 4가 들어가야 할 것이고, 다음 값은 -1이 적용된 형태로 들어가야 한다.
따라서 n -= 1을 통해 다음에 올 3진법의 수에 미리 -1을 수행한다.

아니라면 그대로 수행.

그 후 해당하는 자릿수에 값을 넣어준다.

return str(answer)

구한 값을 String으로 형변환하여 반환하면 끝.

여담

  1. 풀이만 보면 Java로 풀고, 규칙을 깨달은 후 Python으로 푼 것 같지만.. 실상은 반대다. 현재 Java를 공부하면서 알고리즘을 다시 푸는 중. Python 코드를 보고 깜짝 놀랐다.

  2. n -= 1은 생각해보면 굳이 0일때만 해 줄 필요는 없다. 0일 때만 효과가 있는 것일 뿐. 따라서 코드를 더 간결하게 만들 수 있다. 좋아요를 가장 많이 받은 코드들을 보면.. 현타가 올 수 있다.

  3. StringBuffer 사용법도 익힐 겸 Java로도 Python 풀이처럼 풀어보았다.

class Solution {
    public String solution(int n) {
        StringBuffer buff = new StringBuffer();
        int d, r;

        while (n > 0) {
            d = n / 3;
            r = n % 3;

            if (r == 0) {
                r = 4;
                d--;
            }

            buff.append(r);
            n = d;
        }

        return buff.reverse().toString();
    }
}
profile
나누며 타오르는 프로그래머, 타프입니다.

0개의 댓글