1. 문제
programmers.co.kr/learn/courses/30/lessons/67256
문제 설명
이 전화 키패드에서 왼손과 오른손의 엄지손가락만을 이용해서 숫자만을 입력하려고 합니다.
맨 처음 왼손 엄지손가락은 *
키패드에 오른손 엄지손가락은 #
키패드 위치에서 시작하며, 엄지손가락을 사용하는 규칙은 다음과 같습니다.
- 엄지손가락은 상하좌우 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" |
2. 어떻게 풀까?
- 키패드와 현재 왼손, 오른손을 좌표로 생각하여 풀면 될 것 같다.
- 1,4,7은 항상 왼손이고 3,6,9는 항상 오른손이다.
- 2,5,8,0의 경우 해당 number의 좌표와 현재 왼손과 오른손 좌표의 거리를 계산하여 더 가까운 손으로 누르면 되겠다.
- 거리가 같은 경우는 입력으로 주어진 hand를 이용한다.
3. 코드
for문과 if / else if문으로 계속 쓰다보니 바로 됐다. 그 후에 리팩토링을 어떻게 깔끔하게 할 수 있을까 많이 고민했다.
테스트코드
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import org.junit.Test;
public class SolutionTest {
@Test
public void test1() {
int[] numbers = {1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5};
assertThat(new Solution().solution(numbers,"right"), is("LRLLLRLLRRL"));
}
@Test
public void test2() {
int[] numbers = {7, 0, 8, 2, 8, 3, 1, 5, 7, 6, 2};
assertThat(new Solution().solution(numbers,"left"), is("LRLLRRLLLRR"));
}
@Test
public void test3() {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
assertThat(new Solution().solution(numbers,"right"), is("LLRLLRLLRL"));
}
}
실제코드
public class Solution2 {
int[] leftPoint;
int[] rightPoint;
public String solution(int[] numbers, String hand) {
StringBuilder result = new StringBuilder();
leftPoint = new int[]{3, 0};
rightPoint = new int[]{3, 2};
hand = hand.equals("right") ? "R" : "L";
for (int number : numbers) {
touch(result, number, hand);
}
return result.toString();
}
private void touch(StringBuilder result, int number, String hand) {
if (number == 1 || number == 4 || number == 7) {
result.append("L");
leftPoint = getPoint(number);
} else if (number == 3 || number == 6 || number == 9) {
result.append("R");
rightPoint = getPoint(number);
} else if (number == 2 || number == 5 || number == 8 || number == 0) {
String finger = getCloseFinger(number, leftPoint, rightPoint, hand);
result.append(finger);
if (finger.equals("R")) {
rightPoint = getPoint(number);
} else {
leftPoint = getPoint(number);
}
}
}
private String getCloseFinger(int number, int[] leftPoint, int[] rightPoint, String hand) {
int[] padPoint = getPoint(number);
int toLeftFingerDistance =
Math.abs(leftPoint[0] - padPoint[0]) + Math.abs(leftPoint[1] - padPoint[1]);
int toRightFingerDistance =
Math.abs(rightPoint[0] - padPoint[0]) + Math.abs(rightPoint[1] - padPoint[1]);
return toLeftFingerDistance == toRightFingerDistance ? hand
: toLeftFingerDistance < toRightFingerDistance ? "R" : "L";
}
private int[] getPoint(int number) {
if (number == 1) {
return new int[]{0, 0};
} else if (number == 2) {
return new int[]{0, 1};
} else if (number == 3) {
return new int[]{0, 2};
} else if (number == 4) {
return new int[]{1, 0};
} else if (number == 5) {
return new int[]{1, 1};
} else if (number == 6) {
return new int[]{1, 2};
} else if (number == 7) {
return new int[]{2, 0};
} else if (number == 8) {
return new int[]{2, 1};
} else if (number == 9) {
return new int[]{2, 2};
}
return new int[]{3, 1};
}
}
반복문을 돌면서 touch()
메서드로 result
를 계속 붙여나갔다.
touch()
메서드에서는
number
가 1, 4, 7일 경우result
에 "L"을 붙이고 현재 왼손 좌표인leftPoint
를number
에 해당하는 좌표로 수정.- 마찬가지로 3, 6, 9일 경우
result
에 "R"을 붙이고rightPoint
를number
에 해당하는 좌표로 수정한다. number
가 2, 5, 8, 0일 경우getCloseFinger()
메서드를 통해 "L" 또는 "R"을result
에 붙여주고 리턴 값에 따라leftPoint
orrightPoint
를number
에 해당하는 좌표로 수정한다.- 좌표를 수정은
getPoint()
메서드에서 한다.
getCloseFinger()
메서드에서는 number
에 해당하는 좌표와 현재 왼손위치(leftPoint
), 오른손위치(rightPoint
)중 더 가까운 손을 반환 한다.("R" 또는 "L") 만약 거리가 같다면 입력으로 받은 hand
에 따라 결정한다.
4. 느낀점
- 문제 자체는 쉬웠다. 그냥 반복문과 조건문으로 간단하게 풀 수 있었다.
- 그런데, 조건문을 사용하면서 중복되는 코드가 매우 많아져서 코드를 읽기도 어렵고 상당히 복잡했다.
- 그래서 문제를 푸는것 보다 리팩토링하는데 더 고민을 한 문제였다.
- 이 문제 2020 카카오 인턴십때 나온 문제인데 그 당시에는 못풀었다. 이유가 문제만 보고 아 어렵겠다 하고 넘겨서 못풀었는데, 지금 보니까 너무 쉬운문제이다. ㅜㅜ 아쉽
'Coding Test > Programmers' 카테고리의 다른 글
프로그래머스 - 프렌즈 4블록 (12/22) (java) (1) | 2020.12.22 |
---|---|
프로그래머스 - 뉴스 클러스터링 (12/10) (java) (0) | 2020.12.10 |
프로그래머스 - 다트게임(11/16) (java) (0) | 2020.11.16 |
프로그래머스 - 비밀지도(11/11) (java) (0) | 2020.11.11 |
프로그래머스 - 수식 최대화(10/30) (java) (1) | 2020.10.30 |