Algorithm

프로그래머스 - [카카오 인턴] 키패드 누르기

b._.omi 2023. 5. 6. 00:21

 

문제

 

풀이

카카오 인턴쉽 문제답게 상당히 어려운 문제였다. 풀고자 했던 의도는 키패드를 먼저 2차원 평면 좌표로 구현하기 위해 2차원 배열로 좌표들을 지정해 주었고, 현재 왼손 시작 좌표, 오른손 시작 좌표를 지정해 준 다음 numbers 배열들을 좌표에 매칭시켰다.

키패드를 좌표화 한 후 왼손위치와 오른손위치 표시

먼저 1번, 4번, 7번에 해당되는 (1, 0), (2, 0), (3, 0)일 때 "L"을 추가하고

3번, 6번, 9번에 해당되는 (1, 2), (2, 2), (3, 2)일 때 "R"을 추가시킨다.

남은 0번, 2번, 5번, 8번을 처리할 때가 관건인데 이는 예시를 통해 이해해보자

 

왼손 위치가 키패드4번, 오른손 위치가 키패드9번에 있을 때 다음으로 5번 키를 눌러야 하는 상황

유클리드 거리(Euclidean Distance)

9번에서 5번을 가기위해 걸리는 거리는 (1,2)와 (2,1)사이의 거리를 구하기 위해서 유클리드 거리를 계산하기 위해

Math.sqrt(Math.pow(1-2, 2) + Math.pow(2-1, 2)) 의 연산을 했더니 계속 풀리지 않아 의문을 가졌다.

그리고 문제의 예제 설명을 자세히 보니 9번에서 5번으로 가는 거리가 루트2가 아닌 2라고 표기된 것을 발견했다

그제서야 문제 조건에서 손의 위치는 상하좌우로만 이동할 수 있다는 것을 발견했다.... (문제 조건을 확실하게 읽자ㅠ)

즉, 피타고라스 공식을 사용하는 유클리드 거리가 아닌 맨하탄 거리를 이용해서 구해야 한다는 것이었다.

맨하탄 거리(Manhattan Distance)

따라서, x좌표간의 차이 + y좌표간의 차이를 구하면 되기에 Math.abs((1-2) + (2-1)) 로 구현해 주니 해결되었다.

그리고 왼손위치에서 계산한 맨하탄 거리와 오른손위치에서 계산한 맨하탄 거리가 같을 때 왼손잡이이면 "L", 오른손잡이이면 "R"을 추가한다.

 

function solution(numbers, hand) {
    answer = '';
    leftHandPosition = [0, 0];  // 왼손 시작 좌표
    rightHandPosition = [0, 2]; // 오른손 시작 좌표
    
    // numbers 배열을 좌표에 매칭하기 위한 인덱스화
    numbers.map((num, idx) => {
        if(num === 0) return numbers[idx] = 10
        else return numbers[idx]--
    });
    
    // 키패드를 좌표를 그린다 생각하고 2차원 배열로 표현
    let keyCoordinate = [
                            [3, 0], [3, 1], [3, 2], // 1 2 3
                            [2, 0], [2, 1], [2, 2], // 4 5 6
                            [1, 0], [1, 1], [1, 2], // 7 8 9
                            [0, 0], [0, 1], [0, 2]  // * 0 #
                        ];
    
    numbers.map((_, idx) => numbers[idx] = keyCoordinate[numbers[idx]]);
    
    for(let i = 0; i < numbers.length; i++) {
        // numbers[i]가 1, 4, 7 일때, 왼손위치 numbers[i]로 변경, answer에 L 글자 추가
        if(JSON.stringify(numbers[i]) === JSON.stringify([3, 0]) 
           || JSON.stringify(numbers[i]) === JSON.stringify([2, 0]) 
           || JSON.stringify(numbers[i]) === JSON.stringify([1, 0])
          ) {
            leftHandPosition = numbers[i];
            answer += 'L';
        }
        // numbers[i]가 3, 6, 9 일때, 오른손위치 numbers[i]로 변경, answer에 R 글자 추가
        else if(JSON.stringify(numbers[i]) === JSON.stringify([3, 2])
                || JSON.stringify(numbers[i]) === JSON.stringify([2, 2])
                || JSON.stringify(numbers[i]) === JSON.stringify([1, 2])
               ) {
            rightHandPosition = numbers[i];
            answer += 'R';
        }
        // numbers[i]가 0, 2, 5, 8 일때
        else {
            // 왼손위치와 numbers[i]의 거리가 오른손위치와 numbers[i]의 거리보다 짧을 때
            if(Math.abs(leftHandPosition[0] - numbers[i][0]) + Math.abs(leftHandPosition[1] - numbers[i][1])
                < Math.abs(rightHandPosition[0] - numbers[i][0]) + Math.abs(rightHandPosition[1] - numbers[i][1])
              ) {
                leftHandPosition = numbers[i];
                answer += 'L';
            }
            // 오른손위치와 numbers[i]의 거리가 왼손위치와 numbers[i]의 거리보다 짧을 때
            else if(Math.abs(leftHandPosition[0] - numbers[i][0]) + Math.abs(leftHandPosition[1] - numbers[i][1])
                    > Math.abs(rightHandPosition[0] - numbers[i][0]) + Math.abs(rightHandPosition[1] - numbers[i][1])
                    ) {
                rightHandPosition = numbers[i];
                answer += 'R';
            }
            // 왼손위치와 numbers[i]의 거리와 오른손위치와 numbers[i]의 거리가 같을 때
            else {
                if(hand === 'left') {
                    leftHandPosition = numbers[i];
                    answer += 'L'
                }
                else {
                    rightHandPosition = numbers[i];
                    answer += 'R';
                }
            }
        }
    }
    return answer;
}