이 전화 키패드에서 왼손과 오른손의 엄지손가락만을 이용해서 숫자만을 입력하려고 합니다.
맨 처음 왼손 엄지손가락은 * 키패드에 오른손 엄지손가락은 # 키패드 위치에서 시작하며, 엄지손가락을 사용하는 규칙은 다음과 같습니다.
엄지손가락은 상하좌우 4가지 방향으로만 이동할 수 있으며 키패드 이동 한 칸은 거리로 1에 해당합니다.
왼쪽 열의 3개의 숫자 1, 4, 7을 입력할 때는 왼손 엄지손가락을 사용합니다.
오른쪽 열의 3개의 숫자 3, 6, 9를 입력할 때는 오른손 엄지손가락을 사용합니다.
가운데 열의 4개의 숫자 2, 5, 8, 0을 입력할 때는 두 엄지손가락의 현재 키패드의 위치에서 더 가까운 엄지손가락을 사용합니다.
만약 두 엄지손가락의 거리가 같다면, 오른손잡이는 오른손 엄지손가락, 왼손잡이는 왼손 엄지손가락을 사용합니다.
순서대로 누를 번호가 담긴 배열 numbers, 왼손잡이인지 오른손잡이인 지를 나타내는 문자열 hand가 매개변수로 주어질 때, 각 번호를 누른 엄지손가락이 왼손인 지 오른손인 지를 나타내는 연속된 문자열 형태로 return 하도록 solution 함수를 완성해주세요.
numbers | hand | result |
---|---|---|
[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" |
생각보다 풀기 어려운 문제였다. 먼저 키패드를 움직이는 손가락의 거리를 알기 위해서 어떻게 할지부터가 문제였다.
결국 다른 사람들이 푼 문제에서 힌트를 얻을 수 있었다.....
이 문제의 핵심은 손가락이 움직인 거리. 즉, 손가락은 마치 로봇처럼 좌표로 움직이는 것이 핵심이였다.
keyPad라는 객체를 만들어 객체 안에 좌표를 집어넣어 필요한 정보를 꺼내서 사용 할 수 있게 만드는 것을 해야 했다.
그러기 위해서 나만의 증명이 필요했다. 손가락의 위치와 목적지 좌표를 입력하여 그 거리가 손가락이 움직인 횟수가 되는 것인지 확인해야 했다.
거리를 구하는 공식에 대해 증명한 뒤에 keyPad를 만들고 코드를 진행했다. 뒤의 설명은 코드를 따라 설명하겠다.
//아래는 좌표와 좌표 사이의 거리를 알기위해 실험했던 코드.
//let L = [0,0];
//let D = [1,2];
//음수가 나오면 안되기에 절대값을 산출했다.
//let distance = Math.abs(L[0]-D[0] + (L[1]-D[1]));
//console.log(distance)
function solution(numbers, hand){
let answer ='';
//먼저 키패드 마다 좌표로 만들었다. 맨 왼쪽 아래를 0,0에서부터 가장 위쪽은 2,3이다. (가로,세로 길이가 다르기때문에 숫자가 다르다.)
let keyPad = {
//key값에는 각 키패드의 숫자와 문자를 담았다.
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]
}
//우리는 각 손들이 얼마나 움직였는지 알기 위해 각 손이라는 변수를 만들었다.
let leftHand = '*'; //왼손의 초기 위치
let rightHand = '#'; //오른손의 초기 위치
let handU = hand; //손잡이의 초기값
if(handU === 'right'){
handU = 'R'; //오른손 잡이면 R로 바꾼다.
}
if(handU === 'left'){
handU = 'L'; //외손잡이면 L로 바꾼다.
}
//들어온 숫자 길이만큼 반복해서 값을 찾아내고 입력해야한다.
for(let i = 0; i<numbers.length; i++){
//console.log(leftHand) : 오류를 찾기위해 넣었음.
//들어온 숫자가 1,4,7,*이면 answer에 L를 누적시킨다.
if(numbers[i] === 1 || numbers[i]===4 || numbers[i]===7||numbers[i]==='*'){
answer += 'L';
//왼손의 위치를 옮긴다.
leftHand = numbers[i]
}
// 들어온 숫자가 3,6,9,#이면 answer에 R을 누적시킨다.
if(numbers[i] ===3 || numbers[i]===6 ||numbers[i]=== 9||numbers[i]==='#'){
answer += 'R';
//오른손의 위치를 옮긴다.
rightHand = numbers[i]
//console.log(rightHand):오류를 찾기위해 넣음
}
//만약 들어온 숫자가 2, 5, 8, 0이면 아래를 실행한다.
if(numbers[i] === 2||numbers[i]===5||numbers[i]===8||numbers[i]===0){
// 목적지 숫자를 변수에 넣어준다.
let num = numbers[i]
//console.log(num) : 오류를 찾기 위해 넣음
//왼손이 이동한 거리를 구한다.
let distanceL = Math.abs(keyPad[leftHand][0]-keyPad[num][0])+Math.abs((keyPad[leftHand][1]-keyPad[num][1]))
//오른손이 이동한 거리를 구한다.
let distanceR = Math.abs(keyPad[rightHand][0]-keyPad[num][0])+Math.abs((keyPad[rightHand][1]-keyPad[num][1]))
//console.log(distanceL, distanceR) : 오류를 찾기 위해 넣음
// 왼손과 오른손의 이동거리가 같고 왼손잡이면
if(distanceL === distanceR && hand === 'left'){
// 사용자의 해당하는 손을 answer에 누적시키고
answer += handU;
//왼손을 이동시킨다,
leftHand = numbers[i]
}
// 왼손과 오른손의 이동거리가 같고 오른손잡이면
if(distanceL === distanceR && hand === 'right'){
//사용자의 해당하는 손을 answer에 누적시키고
answer += handU;
// 오른손을 이동시킨다.
rightHand = numbers[i]
}
//왼손의 이동거리가 오른손보다 길면
if(distanceL > distanceR){
// 오른손을 이동시키고 R을 누적시킨다.
rightHand = numbers[i]
answer += 'R';
//console.log(rightHand)
}
//왼손의 이동거리가 오른손보다 짧으면
if(distanceL < distanceR){
// 왼손을 이동시키고 L을 누적시킨다.
leftHand = numbers[i]
answer += 'L';
}
}
}
//누적된 answer를 리턴시킨다.
return answer;
}
//값을 확인해보자
console.log(solution([1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5],'right'))
console.log(solution([7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2],'left'))
console.log(solution([1, 2, 3, 4, 5, 6, 7, 8, 9, 0],'right'))
//아래는 keyPad를 가지고 이동거리를 구하기 위해 실험한 것이다.
/*let keyPad1 = {
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]
}
distance1 = Math.abs(keyPad1[0][0]-keyPad1[8][0])+Math.abs((keyPad1[0][1]-keyPad1[8][1]));
//console.log(distance1)
*/
본인이 기술한 방법은 가독성이 매우 떨어지고 한눈에 보기 힘들다는 단점이 있다. 가독성을 높인 방법을 가져왔으며 한번 풀이 해보자.
keyPad의 위치 좌표를 다르게 해석하여 이해하기 힘들었다.
하지만 x 좌표의 움직임으로만 코드를 작성할 수 있어서 편하다.
1 (4, 1) |
2 (4, 0) |
3 (4, 1) |
4 (3, 1) |
5 (3, 0) |
6 (3, 1) |
7 (2, 1) |
8 (2, 0) |
9 (2, 1) |
0 (0, 0) |
위와 같이 알고리즘을 만들면 아래와 같이 계산식에 넣기 수월하다.
function solution(numbers, hand) {
//hand의 매개변수의 앞자가 r이면 R, 아니면 L를 넣는다.
hand = hand[0] === "r" ? "R" : "L"
//위의 도표를 x좌표만 모아두었다. index의 순서와 keyPad의 순서를 맞추었다.
let position = [1, 4, 4, 4, 3, 3, 3, 2, 2, 2]
//손가락 위치의 최초 위치이다.
let h = { L: [1, 1], R: [1, 1] }
//받아온 숫자 배열을 map함수를 사용하여 x를 매개변수 받았다.
return numbers.map(x => {
//1,4,7의 매개변수가 있을경우 참
if (/[147]/.test(x)) {
//왼손을 해당 좌표로 움직인다.
h.L = [position[x], 1]
// 외손이 가르키는 숫자라 L을 리턴한다.
return "L"
}
//3,6,9가 있으면 참
if (/[369]/.test(x)) {
//오른손을 해당 좌표로 움직인다.
h.R = [position[x], 1]
//오른손이 가리키는 숫자라 R을 리턴한다.
return "R"
}
//왼손에서 목적지까지 거리를 구한다. x의 값은 keyPad의 숫자, position[x]는 keypad의 숫자에 해당하는 x좌표를 의미한다.
let distL = Math.abs(position[x] - h.L[0]) + h.L[1]
//오른손에서 목적지까지 거리를 구한다.
let distR = Math.abs(position[x] - h.R[0]) + h.R[1]
//거리가 같다면
if (distL === distR) {
//해당하는 손의 위치를 목적지로 이동 시킨다.
h[hand] = [position[x], 0]
//L 또는 R을 리턴시킨다.
return hand
}
//외손의 거리가 오른손의 거리보다 짧으면
if (distL < distR) {
//외손을 목적지 좌표로 이동시킨다.
h.L = [position[x], 0]
//L을 리턴시킨다.
return "L"
}
//그 외 오른손을 목적지 좌표로 이동시킨다.
h.R = [position[x], 0]
//오른손이 이동하면 R을 리턴한다.
return "R"
//지금까지 리턴한 값을 " "안에 배열을 만든다.
}).join("")
}