[프로그래머스] 조이스틱 - Java

yseo14·2025년 4월 20일

코딩테스트 대비

목록 보기
71/88

문제링크

풀이

세로 조작
가로 조작과 상관 없이 A가 아니면 무조건 해줘야하는 조작이므로 우선 계산해준다.

char c = name.charAt(i);
answer += Math.min(c - 'A', 'Z' - c + 1);

'A'에서 위로 조작하여 변경하는 방법과 아래로 조작하여 'Z'로 돌아가서 변경하는 방법 중 적게 조작하는 방법을 더해준다.

가로 조작
가로 조작 부분은 구현도 까다롭고, 처음엔 이해하기도 어려웠다.
처음에는 커서의 현재 위치에서 왼쪽과 오른쪽 중 더 가까운 'A'가 아닌 문자를 찾아 이동하고, 그 위치에서 다시 같은 과정을 반복하는 방식으로 구현했는데, 이 방법은 성능이 좋지 않아 테스트 통과율이 51.9 / 100에 그쳤다.

그래서 다른 사람들의 풀이를 참고하게 되었고,
그 과정에서 가로 조작의 핵심은 'A'가 연속된 구간을 얼마나 잘 피하느냐에 있다는 것을 이해하게 되었다.

핵심 로직
'조작할 필요 없는 A'가 연속된 구간은 커서 이동을 건너뛸 수 있는 후보다.
따라서 문자열을 왼쪽부터 탐색하면서 A가 길게 이어진 구간을 찾고,
이 구간을 기준으로 앞쪽을 먼저 처리할지, 뒤쪽을 먼저 처리할지를 비교하여
더 짧은 커서 이동 경로를 선택하면 된다.

예시: "ABAABBA"
이 문자열을 예로 들면, 인덱스 1에 있는 B 왼쪽에 A가 두 개 연속으로 존재한다.
그 이후에도 다시 B가 나오는데, 이처럼 A 구간을 기준으로 앞과 뒤를 나눌 수 있다.

  1. 앞쪽을 먼저 처리하는 경우

    • 커서가 0 → 1로 이동해 B를 변경
    • 다시 0으로 돌아감
    • 왼쪽으로 이동하여 문자열의 끝(6번 인덱스)로 이동
    • 이후 6 → 5 → 4(A-B-B) 방향으로 B들을 처리
    move = Math.min(move, i + i + len - next);
  2. 뒤쪽을 먼저 처리하는 경우

    • 커서가 0 → 4로 이동해 B 처리, 이후 5, 6번도 이동하며 처리(B-B-A)
    • 그 다음 커서를 오른쪽으로 한 번 더 이동해 0번으로 순환
    • 다시 1번으로 이동해 앞의 B를 처리
    move = Math.min(move, (len - next) * 2 + i);

위 두 방법을 비교하며 더 작은 값을 구하면 된다.

코드

class Solution {
    public int solution(String name) {
        int answer = 0;
        int len = name.length();
        int move = len - 1; // 최악의 경우: 한쪽 끝까지 쭉 이동

        for (int i = 0; i < len; i++) {
            // 세로 조작 (알파벳 변경)
            char c = name.charAt(i);
            answer += Math.min(c - 'A', 'Z' - c + 1);

            // 가로 조작 (커서 이동 최소화 계산)
            int next = i + 1;
            while (next < len && name.charAt(next) == 'A') {
                next++;
            }

            // i에서 왼쪽으로 갔다가 다시 우회해서 오는 경우 계산
            move = Math.min(move, i + i + len - next);
            // 또는 오른쪽 끝까지 갔다가 왼쪽으로 오는 경우
            move = Math.min(move, (len - next) * 2 + i);
        }
        answer += move;
        return answer;
    }
}
profile
like the water flowing

0개의 댓글