[JAVA] [LEVEL1] 프로그래머스 - 키패드 누르기

반응형

프로그래머스 programmers Level1 키패드 누르기 - java 자바

[문제]

2020 카카오 인턴쉽

https://school.programmers.co.kr/learn/courses/30/lessons/67256

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

[풀이]

간단해 보이면서도 은근 고려해야할 것들이 있었다.

각 키패드 번호에서 누르는 번호까지의 거리 계산이 필요한데, 좌표를 떠올리면 된다.

그러면 이제 좌표를 어떻게 부여할까에 대한 문제가 발생한다.

좌표를 계산하는 방법으로 풀었지만, 미리 배열을 만들어 지정해서 계산하는 방법을 이용해도 된다.

 

키패드는 3열로 이루어져있다. 즉, 좌표로 생각하면 3개의 수가 반복된다는 것이다.

반복된다는 점을 이용해서 인덱스를 3 으로 나눴을 때의 나머지값을 떠올릴 수 있다.

다음과 같이 인덱스화하여 계산하면 일정 패턴을 찾을 수 있다.

좌표 구하기

  • 3 으로 나눴을때
    • 몫은 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 처럼 각 숫자가 3번씩 반복된다. ⇒ x 좌표
    • 나머지는 0, 1, 2 가 반복된다. ⇒ y좌표

도식화 시켜보면 다음과 같은 구조를 띈다.

위의 아이디어를 이용하여 소스를 작성하자.

 

  1. 처음 양 손의 위치를 숫자로 보정해준다.
    왼손 위치( * ) = 10 , 오른손 위치( # ) = 12
  2. 숫자 순서를 확인한다.
    1. 숫자가 1, 4, 7 중 하나이면 왼손 위치를 해당 숫자로 바꿔주고,  L 을 추가한다.
    2. 숫자가 3, 6, 9 중 하나이면 오른손 위치를 해당 숫자로 바꿔주고,  R 을 추가한다.
    3. 숫자가 2, 5, 8, 0 중 하나이면 키패드 숫자까지의 거리를 계산한다.
      1. 양 손의 거리를 계산한다.
        1. 눌러야하는 키패드 숫자가 0인 경우, 10으로 보정해준다.
        2. 다음식으로 거리를 계산한다.
          ・거리 = |x2 - x1| + |y2 - y1|
          ・손의 현재 위치하는 숫자의 좌표 : (x1, y1)
          ・눌러야 하는 키패드 숫자의 좌표 : (x2, y2)
          ・x 좌표 = (숫자 - 1) / 3
          ・y 좌표 = (숫자 - 1) % 3
      2. 오른손이 더 가까운 경우, 오른손 위치를 해당 숫자로 바꿔주고  R 을 추가한다.
      3. 왼손이 더 가까운 경우, 왼손 위치를 해당 숫자로 바꿔주고,  L 을 추가한다.
      4. 양 손의 거리가 동일한 경우
        1. 왼손잡이면, 왼손 위치를 해당 숫자로 바꿔주고,  L 을 추가한다.
        2. 오른손잡이면, 오른손 위치를 해당 숫자로 바꿔주고,  R 을 추가한다

 

[java 코드]

private final static String LEFT_HAND = "L";
private final static String RIGHT_HAND = "R";
private final static String LEFT = "left";

/**
 * 키패드 누르기
 * @param numbers 순서대로 누를 번호가 담긴 배열
 * @param hand 왼손잡이 : left , 오른손잡이 : right
 * @return 각 번호를 누른 손이 왼손인 지 오른손인 지를 나타내는 연속된 문자열 (왼손 L , 오른손 R)
 */
public String solution(int[] numbers, String hand) {
    String answer = "";
    StringBuilder sb = new StringBuilder();
    int leftState = 10; // * 보정 값 10
    int rightState = 12; // # 보정 값 12
    for (int num : numbers) {
        if (num == 1 || num == 4 || num == 7) {
            leftState = num;
            sb.append(LEFT_HAND);
        } else if (num == 3 || num == 6 || num == 9) {
            rightState = num;
            sb.append(RIGHT_HAND);
        } else {
            // 2, 5, 8, 0 인 경우
            int leftDistance = getDistance(leftState, num);
            int rightDistance = getDistance(rightState, num);
            if (leftDistance > rightDistance) {
                // 오른손이 더 가까운 경우
                rightState = num;
                sb.append(RIGHT_HAND);
            } else if (leftDistance < rightDistance) {
                // 왼손이 더 가까운 경우
                leftState = num;
                sb.append(LEFT_HAND);
            } else if (leftDistance == rightDistance) {
                // 거리 동일 한경우 왼손잡이, 오른손잡이 판정
                if (LEFT.equals(hand)) {
                    leftState = num;
                    sb.append(LEFT_HAND);
                } else {
                    rightState = num;
                    sb.append(RIGHT_HAND);
                }
            }
        }
    }
    answer = sb.toString();
    return answer;
}

private int getDistance(int currentState, int target) {
    int result = 0;
    // 0 인경우 11 으로 값 보정
    target = target == 0 ? 11 : target;
    currentState = currentState == 0 ? 11 : currentState;
    // x 좌표 거리 = (숫자 - 1) / 3
    result += Math.abs((currentState - 1) / 3 - (target - 1) / 3);
    // y 좌표 거리 = (숫자 - 1) % 3
    result += Math.abs((currentState - 1) % 3 - (target - 1) % 3);
    return result;
}
반응형