-
[Programmers/Lv1] 키패드 누르기Algorithm/Programmers 2024. 5. 5. 05:30
문제
https://school.programmers.co.kr/learn/courses/30/lessons/67256
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
나의 풀이
- KeyPad 배열을 설정한다.
- handMap 변수에 1, 4, 7 의 값은 "L", 3, 6, 9의 값은 "R"을 매치시킨 후, 해당 번호를 누른 경우 result에 값을 더해준다.
- numbers를 순회하며 handMap의 키에 숫자가 존재할 경우 해당 키의 값을 handMap에서 가져온 후 result에 값을 더해주고, left 혹은 right 변수의 값을 업데이트한다.
- handMap 키에 숫자가 존재하지 않는 경우, keyPad 배열을 해당 숫자가 나올 때까지 순회하며 인덱스를 구하고, left와 right 와 해당 숫자 위치의 거리 차이를 구해 거리가 더 가까운 값을 result에 더한다
- 거리가 동일한 경우, hand 값에 따라 값을 result에 추가해준다.
function solution(numbers, hand) { const keyPad = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ["*", 0, "#"], ]; const handMap = { 1: "L", 4: "L", 7: "L", 3: "R", 6: "R", 9: "R" }; let left = [3, 0]; let right = [3, 2]; let result = ""; numbers.forEach((num) => { const letter = handMap[`${num}`]; if (Object.keys(handMap).includes(`${num}`)) { result += handMap[`${num}`]; keyPad.map((_, i) => { keyPad.map((_, j) => { if (keyPad[i][j] === num) letter === "L" ? (left = [i, j]) : (right = [i, j]); }); }); } else { keyPad.map((_, i) => { keyPad.map((_, j) => { let diff_left = Math.abs(i - left[0]) + Math.abs(j - left[1]); let diff_right = Math.abs(i - right[0]) + Math.abs(j - right[1]); if (keyPad[i][j] === num) { if (diff_left < diff_right) { result += "L"; left = [i, j]; } else if (diff_left > diff_right) { result += "R"; right = [i, j]; } else { if (hand === "right") { result += "R"; right = [i, j]; } else { result += "L"; left = [i, j]; } } } }); }); } }); return result; }다른 사람의 풀이
풀이 제출 후, 좋아요 수가 가장 많은 풀이를 분석해 보았다.
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 => { // 정규식의 test() 메서드가 쓰였다. // 숫자 x가 1,4,7 중 하나와 일치하는 경우 값이 true이다 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("") }* 세로 거리 계산에 용이하도록 position 변수를 두어 층마다 숫자를 부여하였다.

숫자 x가 1,4,7이거나 3,6,9인 경우
** h = 현재 왼쪽 엄지와 오른쪽 엄지의 위치를 추적하는 객체
h 의 첫번째 요소인 세로 값을 position[x] 즉, 키패드의 층 수로 설정해주고
h 의 두번째 요소인 가로 값을 1로 설정해 주는데 그 이유가 처음에 의아했다.
1로 설정해주는 이유는, 키패드 중앙을 기준으로 했을 때
가로의 위치가 왼쪽인지 오른쪽인지는 중요하지 않고, 거리가 1 차이 난다는 것만 명시해주면 되기 때문이다.
왜냐하면 거리 계산은 주어진 숫자가 가운데 위치할 경우만 해주기 때문!
따라서 숫자가 키패드 왼쪽이나 오른쪽에 있는 경우는 값을 1, 가운데에 있는 경우는 값을 0으로 지정해준다.

숫자 x가 2,5,8,0 중 하나인 경우
distL 과 distR을 구해 비교해준다.
숫자의 세로 값 (position[x](세로 값) - h)과 가로값을 더한 후 비교한다.
대소비교에 따라 적절한 문자를 반환한다.
이 경우에 h에는 [position[x], 0]을 대입해준다. 가운데에 위치하기 때문이다.
느낀 점
첫 번째로 키패드 층마다 숫자를 부여해서 세로 값을 지정해주고,
두 번째로 왼쪽이나 오른쪽 숫자의 경우 가로값을 모두 1로 통일해서 방향은 무시하고, 가운데 숫자와의 거리만 명시해줘서
대소비교를 단순화시킨 것이 인상깊었다.
또 배열에 map( )메서드를 사용해서 각 호출 마다 문자를 return해주고 join( ) 메서드로 합쳐준 방식 또한 시도해보지 못한 방식이었다.
코드 길이부터 효율성까지 아직 고칠게 산더미구나 ..