CS/Algorism

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

olsohee 2024. 1. 13. 16:33

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

 

프로그래머스

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

programmers.co.kr

  • 각 자리의 알파벳을 바꾸는 횟수와 자리를 이동하는 횟수를 더하면 된다. 
  • 각 자리의 알파벳을 바꾸는 횟수는 간단하다.
answer += Math.min(name.charAt(i) - 'A', 26 - (name.charAt(i) - 'A'));
  • 자리를 이동하는 횟수를 구하는게 어렵다. 자리를 이동하는 방법은 다음과 같이 3가지가 있다.
    1. 쭉 오른쪽으로 이동
    2. 먼저 오른쪽으로 가다가 왼쪽으로 이동
    3. 먼저 왼쪽으로 가다가 오른쪽으로 이동
  • 연속된 A의 시작과 끝 위치를 찾고, 끝나는 다음 위치인 endA를 찾는다. (ex, BCAAC인 경우 endA는 인덱스 4)
  • 첫 시작 위치는 인덱스 0이다. 
    • 따라서 먼저 오른쪽으로 가다가 왼쪽으로 이동하는 횟수는 i * 2 + name.length() - endA 이다.
    • 그리고 먼저 왼쪽으로 가다가 오른쪽으로 이동하는 횟수는 (name.length() - endA) * 2 + i 이다.
  • 따라서 i = (0 ~ name.length() - 1)의 범위로 for문을 돌면서, 움직이는 횟수를 계속해서 최솟값으로 갱신하면 된다. 
  • BAZAA와 같이 연속된 A가 한 번 나오는게 아니라 여러 번 나올 수 있는데, 이 경우에도 위 알고리즘이 정상적으로 적용되는지가 궁금했다. 그런데, for문을 돌면서 moveCount 값을 계속해서 최솟값으로 갱신하므로 괜찮다! 
    • 쭉 오른쪽으로 이동: 4
    • i = 0, endA = 2
      • 먼저 오른쪽으로 가다가 왼쪽으로 이동: B, A, A, Z = 3
      • 먼저 왼쪽으로 가다가 오른쪽으로 이동: B, A, A, Z, A, A, B = 6
    • i = 2, endA = 5
      • 먼저 오른쪽으로 가다가 왼쪽으로 이동: B, A, Z, A, B = 4
      • 먼저 왼쪽으로 가다가 오른쪽으로 이동: B, A, Z = 2
    • i = 3, endA = 5
      • 먼저 오른쪽으로 가다가 왼쪽으로 이동: B, A, Z, A, Z, A, B = 6
      • 먼저 왼쪽으로 가다가 오른쪽으로 이동: B, A, Z, A = 3
    • 따라서 최소 moveCount = 2
// 시간 복잡도: O(N)
class Solution {

    public int solution(String name) {

        int answer = 0;
        int moveCount = name.length() - 1; // 오른쪽으로 쭉 간 횟수

        for (int i = 0; i < name.length(); i++) {
            answer += Math.min(name.charAt(i) - 'A', 26 - (name.charAt(i) - 'A'));
            if (i < name.length() - 1 && name.charAt(i + 1) == 'A') {
                int endA = i + 1;
                while (endA < name.length() && name.charAt(endA) == 'A') {
                    endA++;
                }
                // endA: 연속된 A가 끝난 다음 인덱스
                moveCount = Math.min(moveCount, i * 2 + (name.length() - endA)); // 오른쪽으로 갔다가 왼쪽으로 간 횟수
                moveCount = Math.min(moveCount, (name.length() - endA) * 2 + i); // 왼쪽으로 갔다가 오른쪽으로 간 횟수
            }
        }
        return answer + moveCount;
    }
}

'CS > Algorism' 카테고리의 다른 글

[백준] 18869. 멀티버스 Ⅱ  (1) 2024.01.18
[백준] 16401. 과자 나눠주기  (0) 2024.01.18
[백준] 1912. 연속합  (0) 2024.01.12
[백준] 15486. 퇴사 2  (0) 2024.01.12
[백준] 11055. 가장 큰 증가하는 부분 수열  (0) 2024.01.09