본문 바로가기

Algorithm

[프로그래머스] 키패드 누르기 with Javascript


키패드 누르기

2020 카카오 인턴십

문제보기

 

제출답안

function solution(numbers, hand) {
    let answer = '';
    let leftHand = '*';
    let rightHand = '#';
    const keypad = [[1, 2, 3], [4, 5, 6], [7, 8, 9], ['*', 0, '#']];
    
    for (let i = 0; i < numbers.length; i++) {
        if ([2, 5, 8, 0].includes(numbers[i])) { // 가운데(2, 5, 8, 0)
            const tmp = [[], [], []]; // 좌표 [왼손, 가운데, 오른손]
            let left = 0;
            let right = 0;
            for (let j = 0; j < 4; j++) {
                for (let k = 0; k < 3; k++) {
                    if (keypad[j][k] === leftHand) {
                        tmp[0].push(j, k);
                    }
                    if (keypad[j][k] === numbers[i]) {
                        tmp[1].push(j, k);
                    }
                    if (keypad[j][k] === rightHand) {
                        tmp[2].push(j, k);
                    }
                }
            }
            left += Math.abs(tmp[0][0] - tmp[1][0]) + Math.abs(tmp[0][1] - tmp[1][1]);
            right += Math.abs(tmp[1][0] - tmp[2][0]) + Math.abs(tmp[1][1] - tmp[2][1]);
            // console.log(`왼위치:${leftHand}, 오른위치:${rightHand}, 가운데 ${numbers[i]}번, 좌표`, tmp);
            if (left === right) {
                answer += hand[0].toUpperCase();
                hand === 'left' ? leftHand = numbers[i] : rightHand = numbers[i];
            } else if (left > right) {
                answer += 'R';
                rightHand = numbers[i];
            } else {
                answer += 'L';
                leftHand = numbers[i];
            }
        } else if ([1, 4, 7].includes(numbers[i])) { // 왼손(1, 4, 7)
            // console.log(`왼위치:${leftHand}, 오른위치:${rightHand}, 왼손으로 ${numbers[i]}번 누르기`);
            answer += 'L';
            leftHand = numbers[i];
        } else { // 오른손(3, 6, 9)
            // console.log(`왼위치:${leftHand}, 오른위치:${rightHand}, 오른손으로 ${numbers[i]}번 누르기`);
            answer += 'R';
            rightHand = numbers[i];
        }
    }

    return answer;
}

 

풀이

  • numbers 배열의 원소를 전체 탐색하기 위해 0부터 (numbers 배열의 길이 - 1)만큼 범위를 가지는 for 반복문 실행 → 순서대로 키패드 누르기
  • numbers[i]의 값에 따라 실행문이 달라지는 if 조건문 실행 → 왼손으로 누를지, 오른손으로 누를지 결정
    • 첫번째 조건 - 중앙에 위치한 2, 5, 8, 0을 누르는 상황
      • 엄지손가락의 현재 위치(leftHand, rightHand)에 따라 numbers[i]를 어느 손으로 누를지 결정하는 코드
      • j와 k의 범위를 갖는 for 반복문을 이중으로 실행 → 왼손, 오른손 엄지손가락의 현재 위치 값과 눌러야할 번호의 위치 값을 확인
      • 왼손 엄지손가락(leftHand)으로부터 눌러야할 번호(numbers[i])까지 거리를 계산하여 left에 저장
      • 오른손 엄지손가락(rightHand)으로부터 눌러야할 번호(numbers[i])까지 거리를 계산하여 right에 저장
      • left와 right 값에 따라 if 조건문 실행
        • 값이 같으면 무슨 손잡이(hand)인지 확인하여 answer에 'L'이나 'R' 더하기
        • answer에 더한 값에 따라 leftHand나 rightHand에 numbers[i] 저장
    • 두번째 조건 - 왼쪽에 위치한 1, 4, 7을 누르는 상황
      • answer에 'L' 더하기 → 왼손 엄지손가락으로 눌렀음을 표시
      • leftHand에 numbers[i] 저장 → 키패드 상에서 왼손 엄지손가락의 현재 위치를 저장
    • 세번째 조건 - 오른쪽에 위치한 3, 6, 9를 누르는 상황
      • answer에 'R' 더하기 → 오른손 엄지손가락으로 눌렀음을 표시
      • rightHand에 numbers[i] 저장 → 키패드 상에서 오른손 엄지손가락의 현재 위치를 저장
  • answer 반환

 

학습내용

Math.abs()를 활용하여 절대값 구하기

해당 번호로부터 각 손가락까지 거리를 구하기 위해서 절대값을 구하는 방식을 활용했다.(본 문제에서는 거리를 구하기 위해 가로, 세로 길이만 활용하는 것 같다)

  • 매개변수로 음수나 양수를 받으면 항상 해당 변수 값의 양수를 반환한다.

조건문 활용방식

이번 문제에서 서로 관련있는 3가지 조건을 필요로 하는 if 조건문을 2번 사용했다. 처음 조건 순서를 작성할 때 제대로 필터링 되지 않았다.

처음 작성한 조건 순서  : if (왼쪽 번호) → else if (오른쪽 번호) → else (중앙 번호), if (right보다 left가 더 클 때) → else if (left보다 right가 더 클 때) → else (left와 right가 서로 같을때)

예를 들어서 numbers[i]가 3일 때 2번째 조건문이 실행돼야 하는데 마지막 조건문에 인식되어 실행되었고, right와 left 값이 같은데 2번째 조건문에서 실행되었다. 정확한 원인을 밝혀내진 못했지만 조건의 순서를 계속 바꿔주다보니 제출한 답안처럼 어느 순간 정확히 맞아 떨어지는 경우가 발생했다. 순서를 바꿔보며 관찰한 결과, 앞으로 조건문을 사용할 때 아래와 같은 원칙을 우선하여 작성해야겠다는 결론을 내렸다.

  • 큰 덩어리의 규모(?)를 가진 조건문을 먼저 작성하자.
  • 조건이 확실한 상황을 먼저 작성하자.

참고

 

Math.abs() - JavaScript | MDN

Math.abs() 함수는 주어진 숫자의 절대값을 반환합니다. x가 양수이거나 0이라면 x를 리턴하고, x가 음수라면 x의 반대값, 즉 양수를 반환합니다.

developer.mozilla.org