처음 풀이
- 전화번호 키패드의 각 숫자의 위치를 어떻게 인식시킬까 하다가 좌표를 떠올렸다.
- 키패드 왼쪽 숫자는 무조건 L, 오른쪽 숫자는 무조건 R이다.
- 가운데 키패드일 경우(2, 5, 8, 0번)는 절대 값 거리를 구해서 더 가까운 쪽을 반영했다.
function solution(numbers, hand) {
let answer = '';
let leftCoord = [3, 0];
let rightCoord = [3, 2];
const one = [0, 0], two = [0, 1], three = [0, 2], four = [1, 0], five = [1, 1]
const six = [1, 2], seven = [2, 0], eight = [2, 1], nine = [2, 2], zero = [3, 1];
for (let number of numbers) {
if (number === 1 || number === 4 || number === 7) {
answer += 'L';
leftCoord = number === 1 ? one : number === 4 ? four : seven;
}
else if (number === 3 || number === 6 || number === 9) {
answer += 'R';
rightCoord = number === 3 ? three : number === 6 ? six : nine;
}
else {
let leftDistance = 0;
let rightDistance = 0;
if (number === 2) {
leftDistance = Math.abs(leftCoord[0] - two[0]) + Math.abs(leftCoord[1] - two[1]);
rightDistance = Math.abs(rightCoord[0] - two[0]) + Math.abs(rightCoord[1] - two[1]);
}
else if (number === 5) {
leftDistance = Math.abs(leftCoord[0] - five[0]) + Math.abs(leftCoord[1] - five[1]);
rightDistance = Math.abs(rightCoord[0] - five[0]) + Math.abs(rightCoord[1] - five[1]);
}
else if (number === 8) {
leftDistance = Math.abs(leftCoord[0] - eight[0]) + Math.abs(leftCoord[1] - eight[1]);
rightDistance = Math.abs(rightCoord[0] - eight[0]) + Math.abs(rightCoord[1] - eight[1]);
} else {
leftDistance = Math.abs(leftCoord[0] - zero[0]) + Math.abs(leftCoord[1] - zero[1]);
rightDistance = Math.abs(rightCoord[0] - zero[0]) + Math.abs(rightCoord[1] - zero[1]);
}
if (leftDistance === rightDistance) {
if (hand === "left") {
answer += 'L';
leftCoord = number === 2 ? two : number === 5 ? five : number === 8 ? eight : zero;
} else {
answer += 'R';
rightCoord = number === 2 ? two : number === 5 ? five : number === 8 ? eight : zero;
}
} else {
if (leftDistance < rightDistance) {
answer += 'L';
leftCoord = number === 2 ? two : number === 5 ? five : number === 8 ? eight : zero;
} else {
answer += 'R';
rightCoord = number === 2 ? two : number === 5 ? five : number === 8 ? eight : zero;
}
}
}
}
return answer;
}
- 처음에 풀 때 문제 테스트 케이스 1번에서 한 글자가 계속 기대값과 다르게 나와서 하나하나 콘솔로 찍어보았다.
- 특정 순간부터 좌표가 갱신되고 있지 않았는데, 마지막에 거리가 같은지 여부를 판별하는 if문에서 answer 값만 바꿔주고 leftCoord 또는 rightCoord 값을 업데이트하지 않은 것이 문제였다.
- 문제의 테스트 케이스를 모두 통과하고 나서 중복되는 로직을 제거하기 위해 다음과 같이 리팩토링했다.
리팩토링
- 고려한 사항
- 선언되는 변수 갯수 줄이기
- 단일 책임 원칙 (SRP)
- 매번 선언될 필요가 없는 함수와 변수는 solution 밖으로 뺌
- 바꾼 코드
const keyCoord = {
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],
0: [3, 1]
}
let leftCoord = [3, 0];
let rightCoord = [3, 2];
function getDistance(number) {
const numberCoord = keyCoord[number];
return {
leftDistance: Math.abs(leftCoord[0] - numberCoord[0]) + Math.abs(leftCoord[1] - numberCoord[1]),
rightDistance: Math.abs(rightCoord[0] - numberCoord[0]) + Math.abs(rightCoord[1] - numberCoord[1])
}
}
function solution(numbers, hand) {
let answer = '';
for (let number of numbers) {
if (number && number % 3 === 1) {
answer += 'L';
leftCoord = keyCoord[number];
}
else if (number && number % 3 === 0) {
answer += 'R';
rightCoord = keyCoord[number];
}
else {
const { leftDistance, rightDistance } = getDistance(number);
if (leftDistance === rightDistance && hand === "left" || leftDistance < rightDistance) {
answer += 'L';
leftCoord = keyCoord[number];
} else {
answer += 'R';
rightCoord = keyCoord[number];
}
}
}
return answer;
}
- else문을 최대한 빼려고 해봤는데 로직이 'A가 아니면 B'라는 구조여서 그런지 에러가 나서 그대로 두었다.
- 처음 코드보다 확실히 가독성이 높아지고 간결해진 것 같다.
(문제 푸는 데 2시간 리팩토링하는 데 1시간)
리팩토링이 재밌었던 문제였다.