[2020 카카오 인턴십] 키패드 누르기 (JAVA)

Jiwoo Kim·2020년 11월 13일
0
post-thumbnail

문제


1차 풀이 (2020.11.14)

시작

쉬운 문제지만 설명이 길어서 일단 쫄았다. 근데 설명이 긴 이유가 어려워서 긴 게 아니라, 설명이 아주 자세해서 긴 것이었다. 그리고 나는 최단거리라는 말만 나오는 쪼는 경향이 있는데 다행히 대각선 뭐 이런 조건 없이 위아래로 왔다 갔다 하고 비교 횟수도 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도 한 칸으로 유지가 되어 있으면 기분이 좋다.

실수

  1. moveHandToTarget()에서 배열 내의 값들을 각각 업데이트하지 않고 currentLeft = target 이딴 식으로 배열 자체를 assign했다. 이런 어이 없는 실수를 스스로 발견하지도 못하고 디버깅까지 찍고 나서야 알아챘다. 집중하자.
  2. 조건 4(더 가까운 손가락 구하는 것)에만 집중하는 바람에 조건 2,3을 깜빡했다. 조건의 존재 자체를 까먹은 건 유죄다. 조건을 잘 읽고 차근차근 구현하자.
  3. ROW랑 COL이랑 헷갈려서 0이 target일 때 position을 잘못 저장했다. 이건 정말 문제를 많이 풀어도 자주 실수할 것 같은 부분이다. 신경쓰자.

새로 배운 것

Switch문 → 람다

수정 전

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];
        }
    }
}

2차 풀이 (2021.05.02)

카카오 인턴 코테 대비를 위해 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;
    }
}

0개의 댓글