키패드 누르기
문제정의
키패드를 어느 쪽 손으로 눌러야 하는 가에 대한 문제이다. 초기 왼손의 위치는 *에 오른손의 위치는 #에 위치해있다. 1,4,7은 무조건 왼손으로 누르고 3,6,9는 오른손으로 누른다. 손가락은 상하좌우로만 움직일 수 있다. 2,5,8,0은 왼손과 오른손 중 더 가까이 있는 손가락으로 누르며, 만약 두 손가락이 움직이는 거리가 같은 경우 주로 쓰는 손으로 누른다. 눌러야할 번호들이 주어지면 어느쪽 손으로 누르는지 "L"과 "R"로 구성된 문자열로 나타내라.
## 문제풀이
전체 코드는 다음과 같다. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64public class KeyPad {
public static void main(String[] args)
{
int[] numbers = {1, 3, 4, 5, 8, 2, 1, 4, 5, 9, 5};
String hand = "right";
StringBuilder buff = new StringBuilder();
int left_pos = 10, right_pos = 11;
boolean isleft = false;
int[][] moves = {
{0, -1, 3, -1, -1, 2, -1, -1, 1, -1}, //0
{4, -1, 1, -1, -1, 2, -1, -1, 3, -1}, //1
{3, -1, 0, -1, -1, 1, -1, -1, 2, -1}, //2
{4, -1, 1, -1, -1, 2, -1, -1, 3, -1}, //3
{3, -1, 2, -1, -1, 1, -1, -1, 2, -1}, //4
{2, -1, 1, -1, -1, 0, -1, -1, 1, -1}, //5
{3, -1, 2, -1, -1, 1, -1, -1, 2, -1}, //6
{2, -1, 3, -1, -1, 2, -1, -1, 1, -1}, //7
{1, -1, 2, -1, -1, 1, -1, -1, 0, -1}, //8
{2, -1, 3, -1, -1, 2, -1, -1, 1, -1}, //9
{1, -1, 4, -1, -1, 3, -1, -1, 2, -1}, //10(*)
{1, -1, 4, -1, -1, 3, -1, -1, 2, -1} //11(#)
};
for(int num : numbers)
{
if(num == 1 || num == 4 || num == 7)
isleft = true;
else if(num == 3 || num == 6 || num == 9)
isleft = false;
else
{
int left_dist = moves[left_pos][num];
int right_dist = moves[right_pos][num];
if(left_dist < right_dist)
isleft = true;
else if(right_dist < left_dist)
isleft = false;
else
{
if(hand.equals("left"))
isleft = true;
else
isleft = false;
}
}
if(isleft)
{
buff.append("L");
left_pos = num;
}
else
{
buff.append("R");
right_pos = num;
}
}
String answer = buff.toString();
System.out.print(answer);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17StringBuilder buff = new StringBuilder();
int left_pos = 10, right_pos = 11;
boolean isleft = false;
int[][] moves = {
{0, -1, 3, -1, -1, 2, -1, -1, 1, -1}, //0
{4, -1, 1, -1, -1, 2, -1, -1, 3, -1}, //1
{3, -1, 0, -1, -1, 1, -1, -1, 2, -1}, //2
{4, -1, 1, -1, -1, 2, -1, -1, 3, -1}, //3
{3, -1, 2, -1, -1, 1, -1, -1, 2, -1}, //4
{2, -1, 1, -1, -1, 0, -1, -1, 1, -1}, //5
{3, -1, 2, -1, -1, 1, -1, -1, 2, -1}, //6
{2, -1, 3, -1, -1, 2, -1, -1, 1, -1}, //7
{1, -1, 2, -1, -1, 1, -1, -1, 0, -1}, //8
{2, -1, 3, -1, -1, 2, -1, -1, 1, -1}, //9
{1, -1, 4, -1, -1, 3, -1, -1, 2, -1}, //10(*)
{1, -1, 4, -1, -1, 3, -1, -1, 2, -1} //11(#)
};
1 | for(int num : numbers) |
논리적으로 어려운 부분은 없다. 1,4,7인경우에는 왼손으로 누르므로 isleft를 true값으로 변경한다. 3,6,9인 경우 false로 바꾼다. 만약 중간에 있는 키패드인 경우 moves 값을 비교하여 판별한다. 만약 값이 같은 경우 어느 손잡이인지 보면 된다. 키패드를 누를 때마다 현재 있어야 하는 위치값을 업데이트 하는 것을 잊지 말자. numbers의 길이를 n이라고 하면 이 알고리즘의 시간복잡도는 \(O(n)\)이다.
테스트
옛날에 멋모르고 인턴에 지원했다가 이 문제만 2-3시간 풀고 포기한 경험이 있다. 그래서 그 때의 안 좋은 감정이 차올랐는데, 이번에는 30분정도 걸렸다. 내가 성장하고 있는 걸 느껴서 기쁘다. 첨언을 하자면 키패드를 자세히 보면 3으로 나머지연산과 나누기 연산을 하면 키패드의 어느 위치에 있는지 쉽게 알 수 있다. 이걸 활용하면 코드를 더 간결하게 만들 수 있을거라 생각한다.