쉬운 문제지만 설명이 길어서 일단 쫄았다. 근데 설명이 긴 이유가 어려워서 긴 게 아니라, 설명이 아주 자세해서 긴 것이었다. 그리고 나는 최단거리라는 말만 나오는 쪼는 경향이 있는데 다행히 대각선 뭐 이런 조건 없이 위아래로 왔다 갔다 하고 비교 횟수도 2번 밖에 되지 않아서 잘 풀 수 있었다.
손과 버튼의 위치는 2차원 배열에서 ROW, COL로 표현하였고, 손가락의 위치를 담을 변수와 타겟 위치를 담을 static 변수를 먼저 만들었다. 작동 순서는 어느 손인지 알아내고 → 움직이고(업데이트하고) → 결과출력하는 것으로 구상을 해서 각 메소드를 만들었다.
setHanded()
handed
는 왼손/오른손잡이를 나타내는 변수다. 초기 parameter로 넘어오는 값인데, 이미 인수로 넘어왔던 값을 또 인수로 넘기기 싫고, 함수 단계가 깊어질 것 같아서 static으로 선언했다.
출력에서 원하는 형태인 R
이나 L
로 바로 반환하기 위해 본 메소드에서 적절하게 변환해서 저장한다.
setTargetPosition()
타켓(number)의 좌표를 만들어 static 변수에 저장하는 메소드다. ROW는 위에서부터 0~3, COL은 왼쪽부터 0~2로 지정했다. 번호가 일정하게 3 단위로 나뉘어져 있는 것이 눈에 잘 보여서 바로 몫과 나머지를 활용해서 ROW와 COL 번호를 알아낼 수 있었다.
다른 메소드들은 딱히 설명이 없어도 직관적으로 이해할 수 있을 것 같다. 클린코드 책을 읽은 이후 함수가 4줄 이내로 정리되고 indent도 한 칸으로 유지가 되어 있으면 기분이 좋다.
moveHandToTarget()
에서 배열 내의 값들을 각각 업데이트하지 않고 currentLeft = target
이딴 식으로 배열 자체를 assign했다. 이런 어이 없는 실수를 스스로 발견하지도 못하고 디버깅까지 찍고 나서야 알아챘다. 집중하자.수정 전
private String getNextMoveHand(int number) {
switch (number) {
case 1:
case 4:
case 7:
return "L";
case 3:
case 6:
case 9:
return "R";
default:
return getNextMoveHandByDistance();
}
}
수정 후
private String getNextMoveHand(int number) {
return switch (number) {
case 1, 4, 7 -> "L";
case 3, 6, 9 -> "R";
default -> getNextMoveHandByDistance();
};
}
인텔리제이가 알아서 고쳐줬다. 역시 똑똑한 IDE다.
Spring Boot 쓰면서 리턴문 자체에 람다식을 넣는 것을 몇 번 봤는데 아직 람다 문법을 정확하게 몰라서 IDE가 고치는 수준만 이해할 수 있다. 부끄럽다. 람다문 공부를 해야겠다.
class Solution {
static final int ROW = 0;
static final int COL = 1;
static int[] currentLeft = {3, 0};
static int[] currentRight = {3, 2};
static int[] target = new int[2];
static String handed;
public String solution(int[] numbers, String hand) {
setHanded(hand);
StringBuilder sb = new StringBuilder();
for (int number : numbers) {
setTargetPosition(number);
String nextMoveHand = getNextMoveHand(number);
moveHandToTarget(nextMoveHand);
sb.append(nextMoveHand);
}
return sb.toString();
}
private void setHanded(String hand) {
if (hand.equals("right")) handed = "R";
else handed = "L";
}
private String getNextMoveHand(int number) {
return switch (number) {
case 1, 4, 7 -> "L";
case 3, 6, 9 -> "R";
default -> getNextMoveHandByDistance();
};
}
private String getNextMoveHandByDistance() {
int leftDistance = getDistanceForLeft();
int rightDistance = getDistanceForRight();
return getCloserHand(leftDistance, rightDistance);
}
private void setTargetPosition(int number) {
target[ROW] = (number - 1) / 3;
target[COL] = (number + 2) % 3;
if (number == 0) {
target[ROW] = 3;
target[COL] = 1;
}
}
private int getDistanceForLeft() {
int rowDistance = Math.abs(currentLeft[ROW] - target[ROW]);
int colDistance = Math.abs(currentLeft[COL] - target[COL]);
return rowDistance + colDistance;
}
private int getDistanceForRight() {
int rowDistance = Math.abs(currentRight[ROW] - target[ROW]);
int colDistance = Math.abs(currentRight[COL] - target[COL]);
return rowDistance + colDistance;
}
private String getCloserHand(int leftDistance, int rightDistance) {
if (leftDistance > rightDistance) return "R";
else if (leftDistance < rightDistance) return "L";
else return handed;
}
private void moveHandToTarget(String nextMove) {
if (nextMove.equals("R")) {
currentRight[ROW] = target[ROW];
currentRight[COL] = target[COL];
} else if (nextMove.equals("L")) {
currentLeft[ROW] = target[ROW];
currentLeft[COL] = target[COL];
}
}
}
카카오 인턴 코테 대비를 위해 2020 인턴 코테 기출을 다시 풀기 시작했다. int[]로 position을 미리 계산해놓으니 코드가 더 직관적으로 변했다.
반 년 전에 짠 코드보다 지금 짠 코드가 확실히 더 나은 것 같다. getDistanceForLeft()
, getDistanceForRight()
머 이렇게 같은 내용의 함수를 두 개로 분리해놓은 것도 파라미터를 활용했으면 더 간단했을텐데 쓸데없이 static으로 사용하느라 코드가 더 복잡해졌던 것 같다.
class Solution {
private static final int ROW = 0;
private static final int COL = 1;
private int[] currentLeft = {3, 0};
private int[] currentRight = {3, 2};
public String solution(int[] numbers, String hand) {
StringBuilder sb = new StringBuilder();
for (int number : numbers)
sb.append(push(number, hand));
return sb.toString();
}
private char push(int number, String handed) {
int[] target = getPosition(number);
char hand = whichHand(target, handed);
moveHandToNumber(target, hand);
return hand;
}
private char whichHand(int[] target, String handed) {
if (target[COL] == 0) return 'L';
else if (target[COL] == 2) return 'R';
char hand;
int leftDist = dist(currentLeft, target);
int rightDist = dist(currentRight, target);
if (leftDist < rightDist) hand = 'L';
else if (leftDist > rightDist) hand = 'R';
else hand = (handed.equals("left") ? 'L' : 'R');
return hand;
}
private int dist(int[] current, int[] target) {
return Math.abs(current[ROW] - target[ROW])
+ Math.abs(current[COL] - target[COL]);
}
private int[] getPosition(int targetNumber) {
int[] position = new int[2];
if (targetNumber == 0) {
position[ROW] = 3;
position[COL] = 1;
} else if (targetNumber % 3 == 1) {
position[ROW] = targetNumber / 3;
position[COL] = 0;
} else if (targetNumber % 3 == 2) {
position[ROW] = targetNumber / 3;
position[COL] = 1;
} else if (targetNumber % 3 == 0) {
position[ROW] = targetNumber / 3 - 1;
position[COL] = 2;
}
return position;
}
private void moveHandToNumber(int[] target, char hand) {
if (hand == 'L') currentLeft = target;
else if (hand == 'R') currentRight = target;
}
}