[프로그래머스] 키패드 누르기 (2020 카카오 인턴십)
2022. 11. 30. 13:38ㆍ기록/Programmers
- 목차
문제 설명
스마트폰 전화 키패드의 각 칸에 다음과 같이 숫자들이 적혀 있습니다.
이 전화 키패드에서 왼손과 오른손의 엄지손가락만을 이용해서 숫자만을 입력하려고 합니다.
맨 처음 왼손 엄지손가락은 * 키패드에 오른손 엄지손가락은 # 키패드 위치에서 시작하며, 엄지손가락을 사용하는 규칙은 다음과 같습니다.
- 엄지손가락은 상하좌우 4가지 방향으로만 이동할 수 있으며 키패드 이동 한 칸은 거리로 1에 해당합니다.
- 왼쪽 열의 3개의 숫자 1, 4, 7을 입력할 때는 왼손 엄지손가락을 사용합니다.
- 오른쪽 열의 3개의 숫자 3, 6, 9를 입력할 때는 오른손 엄지손가락을 사용합니다.
- 가운데 열의 4개의 숫자 2, 5, 8, 0을 입력할 때는 두 엄지손가락의 현재 키패드의 위치에서 더 가까운 엄지손가락을 사용합니다.
4-1. 만약 두 엄지손가락의 거리가 같다면, 오른손잡이는 오른손 엄지손가락, 왼손잡이는 왼손 엄지손가락을 사용합니다.
순서대로 누를 번호가 담긴 배열 numbers, 왼손잡이인지 오른손잡이인 지를 나타내는 문자열 hand가 매개변수로 주어질 때, 각 번호를 누른 엄지손가락이 왼손인 지 오른손인 지를 나타내는 연속된 문자열 형태로 return 하도록 solution 함수를 완성해주세요.
제한 사항
- numbers 배열의 크기는 1 이상 1,000 이하입니다.
- numbers 배열 원소의 값은 0 이상 9 이하인 정수입니다.
- hand는 "left" 또는 "right" 입니다.
- "left"는 왼손잡이, "right"는 오른손잡이를 의미합니다.
- 왼손 엄지손가락을 사용한 경우는 L, 오른손 엄지손가락을 사용한 경우는 R을 순서대로 이어붙여 문자열 형태로 return 해주세요.
입출력 예
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" |
입출력 예 설명
입출력 예 #1
순서대로 눌러야 할 번호가 [1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5]이고, 오른손잡이입니다.
왼손 위치오른손 위치눌러야 할 숫자사용한 손설명
* | # | 1 | L | 1은 왼손으로 누릅니다. |
1 | # | 3 | R | 3은 오른손으로 누릅니다. |
1 | 3 | 4 | L | 4는 왼손으로 누릅니다. |
4 | 3 | 5 | L | 왼손 거리는 1, 오른손 거리는 2이므로 왼손으로 5를 누릅니다. |
5 | 3 | 8 | L | 왼손 거리는 1, 오른손 거리는 3이므로 왼손으로 8을 누릅니다. |
8 | 3 | 2 | R | 왼손 거리는 2, 오른손 거리는 1이므로 오른손으로 2를 누릅니다. |
8 | 2 | 1 | L | 1은 왼손으로 누릅니다. |
1 | 2 | 4 | L | 4는 왼손으로 누릅니다. |
4 | 2 | 5 | R | 왼손 거리와 오른손 거리가 1로 같으므로, 오른손으로 5를 누릅니다. |
4 | 5 | 9 | R | 9는 오른손으로 누릅니다. |
4 | 9 | 5 | L | 왼손 거리는 1, 오른손 거리는 2이므로 왼손으로 5를 누릅니다. |
5 | 9 | - | - |
따라서 "LRLLLRLLRRL"를 return 합니다.
입출력 예 #2
왼손잡이가 [7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2]를 순서대로 누르면 사용한 손은 "LRLLRRLLLRR"이 됩니다.
입출력 예 #3
오른손잡이가 [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]를 순서대로 누르면 사용한 손은 "LLRLLRLLRL"이 됩니다.
나의 문제 풀이
function solution(numbers, hand) {
const answer = [];
const left = [1, 4, 7];
const right = [3, 6, 9];
const center = [2, 5, 8, 0];
const move = [[], [1, 2, 3, 4], [0, 1, 2, 3], [1, 2, 3, 4], [2, 1, 2, 3], [1, 0, 1, 2], [2, 1, 2, 3], [3, 2, 1, 2], [2, 1, 0, 1], [3, 2, 1, 2], [4, 3, 2, 1], [3, 2, 1, 0], [4, 3, 2, 1]];
let curLeft = 10;
let curRight = 12;
for (let i = 0; i < numbers.length; i++) {
if (left.includes(numbers[i])) {
answer.push('L');
} else if (right.includes(numbers[i])) {
answer.push('R');
} else {
let idx = center.indexOf(numbers[i]);
if (move[curLeft][idx] < move[curRight][idx]) {
answer.push('L');
} else if (move[curLeft][idx] > move[curRight][idx]) {
answer.push('R');
} else {
if (hand === 'left') answer.push('L');
else answer.push('R');
}
}
const direction = answer[answer.length - 1];
if (numbers[i] === 0) {
if (direction === 'L') curLeft = 11;
else curRight = 11;
} else {
if (direction === 'L') curLeft = numbers[i];
else curRight = numbers[i];
}
}
return answer.join('');
}
- left 배열 변수 : 왼손으로 누를 숫자
- right 배열 변수 : 오른손으로 누를 숫자
- center 배열 변수 : 가운데 있는 숫자
- move 배열 변수
- 인덱스 : 현재 손가락이 위치한 숫자
- 값: 해당 숫자에서부터 가운데 있는 숫자인 2, 5, 8, 0 까지의 거리
- 숫자는 1부터 시작하기 때문에 0번째 인덱스 요소는 비워두었음
- curLeft : 현재 왼쪽 손가락이 위치한 숫자 (* 를 10 으로 표현)
- curRight : 현재 오른쪽 손가락이 위치한 숫자 (# 를 12 로 표현)
- 0부터 주어진 numbers 배열의 길이까지 반복한다.
- 현재 숫자가 left 배열 변수에 존재할 경우 정답 배열에 "L" 을 넣는다.
- 현재 숫자가 right 배열 변수에 존재할 경우 정답 배열에 "R" 을 넣는다.
- 현재 숫자가 left, right 배열 변수에 존재하지 않는 경우
- 가운데 있는 숫자들 중에 하나임
- center 배열에서 현재 숫자의 인덱스를 찾음
- move 배열에서 현재 왼쪽/오른쪽 손가락의 위치, 현재 가운데 숫자를 인덱스로 거리를 구함
- 왼쪽 손가락에서부터 현재 가운데 숫자까지의 거리가 더 작을 경우 정답 배열에 "L" 을 넣는다.
- 오른쪽 손가락에서부터 현재 가운데 숫자까지의 거리가 더 작을 경우 정답 배열에 "R" 을 넣는다.
- 두 거리가 같을 경우 왼손잡이면 정답 배열에 "L", 오른손잡이면 정답 배열에 "R" 을 넣는다.
- 가장 마지막으로 정답 배열에 넣은 값을 찾는다.
- 현재 숫자가 0일 경우
- 가장 마지막으로 정답 배열에 넣은 값이 "L" 일 경우 현재 왼쪽 손가락 위치 변수에 11 을 넣는다.
- 아닐 경우 "R" 이기 때문에 현재 오른쪽 손가락 위치 변수에 11 을 넣는다.
- 현재 숫자가 0이 아닐 경우
- 가장 마지막으로 정답 배열에 넣은 값이 "L" 일 경우 현재 왼쪽 손가락 위치 변수에 현재 숫자를 넣는다.
- 아닐 경우 "R" 이기 때문에 현재 오른쪽 손가락 위치 변수에 현재 숫자를 넣는다.
- 정답 배열 변수를 문자열로 이어서 반환한다.
다른 사람의 문제 풀이
function solution(numbers, hand) {
hand = hand[0] === "r" ? "R" : "L"
let position = [1, 4, 4, 4, 3, 3, 3, 2, 2, 2]
let h = { L: [1, 1], R: [1, 1] }
return numbers.map(x => {
if (/[147]/.test(x)) {
h.L = [position[x], 1]
return "L"
}
if (/[369]/.test(x)) {
h.R = [position[x], 1]
return "R"
}
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]
return hand
}
if (distL < distR) {
h.L = [position[x], 0]
return "L"
}
h.R = [position[x], 0]
return "R"
}).join("")
}
const solution = (numbers, hand) => {
const answer = [];
let leftHandPosition = '*';
let rightHandPosition = '#';
numbers.forEach(number => {
if (number === 1 || number === 4 || number === 7) {
answer.push('L');
leftHandPosition = number;
return;
}
if (number === 3 || number === 6 || number === 9) {
answer.push('R');
rightHandPosition = number;
return;
}
const leftHandDistance = getDistance(leftHandPosition, number);
const rightHandDistance = getDistance(rightHandPosition, number);
if (leftHandDistance === rightHandDistance) {
if (hand === "right") {
answer.push('R');
rightHandPosition = number;
return;
}
if (hand === 'left') {
answer.push('L');
leftHandPosition = number;
return;
}
}
if (leftHandDistance > rightHandDistance) {
answer.push('R');
rightHandPosition = number;
}
if (leftHandDistance < rightHandDistance) {
answer.push('L');
leftHandPosition = number;
}
});
return answer.join("");
};
const getDistance = (locatedNumber, target) => {
const keyPad = {
1: [0, 0], 2: [0, 1], 3: [0, 2],
4: [1, 0], 5: [1, 1], 6: [1, 2],
7: [2, 0], 8: [2, 1], 9: [2, 2],
'*': [3, 0], 0: [3, 1], '#': [3, 2],
}
const nowPosition = keyPad[locatedNumber];
const targetPosition = keyPad[target];
return Math.abs(targetPosition[0] - nowPosition[0]) + Math.abs(targetPosition[1] - nowPosition[1]);
};
const transpose = matrix =>
matrix.reduce(
(result, row) => row.map((_, i) => [...(result[i] || []), row[i]]),
[]
);
const solution = (board, moves) => {
const stacks = transpose(board).map(row =>
row.reverse().filter(el => el !== 0)
);
const basket = [];
let result = 0;
for (const move of moves) {
const pop = stacks[move - 1].pop();
if (!pop) continue;
if (pop === basket[basket.length - 1]) {
basket.pop();
result += 2;
continue;
}
basket.push(pop);
}
return result;
};
function solution(numbers, hand) {
const basicNumbers = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
['*', 0, '#'],
];
let firstFingerPos = {
L: [3, 0],
R: [3, 2],
};
const numberIdxs = basicNumbers
.map((arr, rowIdx) => {
return arr.map((el, colNum) => {
return [rowIdx, colNum];
});
})
.flat();
let result = [];
numbers.reduce((p, c) => {
const number = c;
const fingerL = p['L'];
const fingerR = p['R'];
const numberPos = numberIdxs[(number || 11) - 1];
const numberR = numberPos[0];
const numberC = numberPos[1];
if (numberC === 0) {
result.push('L');
p['L'] = numberPos;
} else if (numberC === 2) {
result.push('R');
p['R'] = numberPos;
} else {
const lengthL = Math.abs(fingerL[0] - numberR) + Math.abs(fingerL[1] - numberC);
const lengthR = Math.abs(fingerR[0] - numberR) + Math.abs(fingerR[1] - numberC);
const handLR = lengthL === lengthR ? (hand === 'right' ? 'R' : 'L') : lengthL > lengthR ? 'R' : 'L';
result.push(handLR);
p[handLR] = numberPos;
}
return p;
}, firstFingerPos);
return result.join('');
}