본문 바로가기

Algorithm

[프로그래머스/js] 키패드 누르기

이 문제는 그림이 나와서 그런지 푸는데 아기자기하고 즐거웠다

(즐거웠다는 의미가 절대 쉬웠다는 의미는 아닙니다만)

 

코딩테스트 연습 - 키패드 누르기

[1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5] "right" "LRLLLRLLRRL" [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2] "left" "LRLLRRLLLRR" [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] "right" "LLRLLRLLRL"

programmers.co.kr

 

내가 생각했을 때 이 문제를 풀면서 중요한 건 두가지였는데

1. 양 손가락의 마지막 위치가 어디인지

2. 키패드 간의 거리를 어떤 공식으로 구할 것인지

 

1번같은 경우는 map을 사용해서 양 손의 마지막 클릭 버튼을 업데이트 해주었다

   let handsLocation = new Map([
        ["R","#"],
        ["L","*"]
    ]);

문제는 2번이었는데. 거리를 구한다는 말에 유클리드 거리 구하는 공식으로 계산했는데(대각선 구할 때 써야함)

문제에 손가락은 상하좌우로 이동한다고 나와있었기 때문에 유클리드가 아니라 맨해튼 거리를 사용해

거리를 구해야했던 것

const absDis = Math.floor(Math.sqrt(Math.pow(Math.abs(a1-b1),2) + Math.pow(Math.abs(a2-b2),2)))

이렇게 유클리드로 열심히 구했는데 계속 실패 떠서 다 콘솔 찍었는데 허망했다.

 const absDis = Math.floor( Math.abs(a1 - b1) + Math.abs(a2 - b2))

이렇게 구하는 것이 맞았다.

이 밖에는 따로 어려움은 없었던 것같다.


우선 무조건 오른손/왼손을 사용하는 경우와 각 숫자 패드의 좌표를 선언해준다

const left = [1,4,7];
const right = [3,6,9];

const keys = {
    1: [0,3], 2:[1,3], 3:[2,3],
    4: [0,2], 5:[1,2], 6:[2,2],
    7: [0,1], 8:[1,1], 9:[2,1],
    '*': [0,0], 0:[1,0], '#':[2,0]
}

입력받은 numbers를 for문을 돌려 차례대로 어떤 손을 써야하는지 확인하여 

마지막 손가락의 위치를 업데이트해주고 answer 배열에 추가해준다.

const setValues = (hand,num) => {
    handsLocation.set(hand,num);
    answer.push(hand)
}

for (let number of numbers) {
        if (left.includes(number)) {
            setValues("L",number);
        } else if (right.includes(number)) {
            setValues("R",number);
        } else {
           selHand(number) 
        }
    }

왼손에도 오른손에도 속하지 않는 번호는 else 문에서 처리하는데 

코드 길어지는게 싫어서 따로 selHand로 뺐다

const selHand = (num) => {
    const fromL = calDistance(handsLocation.get("L"),num);
    const fromR = calDistance(handsLocation.get("R"),num);
    const handChar = hand === "right" ? "R" :"L"

     if (fromL == fromR) {
         return setValues(handChar,num);
     }

    return fromL < fromR ? setValues("L",num) : setValues("R",num);

}

fromL과 fromR로 직전위치 - 숫자까지의 거리를 각각 계산하여 비교한다.

 const calDistance =(k1,k2) => {
        const a = keys[k1];
        const b = keys[k2];
         
        const a1 = a[0];
        const a2 = a[1];
        const b1 = b[0];
        const b2 = b[1];
        
        const absDis = Math.floor( Math.abs(a1 - b1) + Math.abs(a2 - b2))
     
        return absDis
    }

calDistanse에서 두 숫자를 받아 각각의 좌표를 구하고 절대 거리를 리턴한다.

function solution(numbers, hand) {
    const answer = [];
    const left = [1,4,7];
    const right = [3,6,9]
    
    let handsLocation = new Map([
        ["R","#"],
        ["L","*"]
    ]);
    
    const keys = {
        1: [0,3], 2:[1,3], 3:[2,3],
        4: [0,2], 5:[1,2], 6:[2,2],
        7: [0,1], 8:[1,1], 9:[2,1],
        '*': [0,0], 0:[1,0], '#':[2,0]
    }
    
    const setValues = (hand,num) => {
        handsLocation.set(hand,num);
        answer.push(hand)
    }
    
     const calDistance =(k1,k2) => {
        const a = keys[k1];
        const b = keys[k2];
         
        const a1 = a[0];
        const a2 = a[1];
        const b1 = b[0];
        const b2 = b[1];
        
        const absDis = Math.floor( Math.abs(a1 - b1) + Math.abs(a2 - b2))
     
        return absDis
    }
    
    const selHand = (num) => {
        const fromL = calDistance(handsLocation.get("L"),num);
        const fromR = calDistance(handsLocation.get("R"),num);
        const handChar = hand === "right" ? "R" :"L"
        
         if (fromL == fromR) {
             return setValues(handChar,num);
         }
        
        return fromL < fromR ? setValues("L",num) : setValues("R",num);
        
    }
    
    for (let number of numbers) {
        if (left.includes(number)) {
            setValues("L",number);
        } else if (right.includes(number)) {
            setValues("R",number);
        } else {
           selHand(number) 
        }
    }
   return answer.join('')
}

마지막에 ['R','L','R','R'] 형태로 저장된 배열을 string으로 바꿔줘야 해서 join('')을 사용했다