kangyuseok 2024. 1. 9. 15:01
728x90

문제

 

프로그래머스

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

programmers.co.kr

조이스틱을 최소로 움직여서 알파벳을 만드는 문제이다. 

처음 알파벳은 글자 수 * "A" 로 설정한다. (ex : "JAZ" 이면 처음 알파벳은 "AAA")

 

먼저 내가 문제를 풀면서 처음에 생각한 방법이다.

1. 먼저 check 배열을 통해 바꿀 알파벳을 찾는다. (A는 바꿀 필요없음)

2. 현재 위치(index = 0)에서 가장 가까운 곳을 찾고 이동한다. (왼쪽, 오른쪽)

3. 이동한 위치에서 상하로 알파벳을 최소로 이동하면서 바꿈(위, 아래)

 

2 ~ 3 반복

이에 따라 아래 코드는 내가 작성한 코드이다.

import java.util.*;
class Solution {
    private static int []targetAlphabet;
    private static boolean[]change;
    private static int answer;
    public int solution(String name) {
        targetAlphabet = new int[name.length()];
        change = new boolean[name.length()]; //true이면 바꿔야됨
        
        int numberOfChange = 0; //바꿔야 하는 알파벳 개수
        
        //1
        for(int i=0;i<targetAlphabet.length;i++){
            if(name.charAt(i)!='A'){
                change[i] = true;
                numberOfChange++; 
            }
            targetAlphabet[i] = name.charAt(i)-'A';
        }
        
        answer = 0;
        int index = 0;

        int temp = 0;
        for(int i=0;i<numberOfChange;i++){
            temp = index;
            index = findNearest(temp); //2
            answer += changeAlphabet(index); //3
        }
        return answer;
    }
    private static int findNearest(int idx){
        int frontIdx = idx;
        int backIdx = idx;
        
        int finalIdx = -1;
        while(true){
            if(change[frontIdx]){
                change[frontIdx]=false;
                finalIdx = frontIdx;
                break;
            }
            else if(change[backIdx]){
                change[backIdx]=false;
                finalIdx = backIdx;
                break;
            }
            else{
                frontIdx++;
                backIdx--;
                if(frontIdx == change.length)frontIdx = 0;
                if(backIdx < 0)backIdx = change.length-1;
                answer++;
            }
        }
        return finalIdx;
    }
    
    private static int changeAlphabet(int idx){
        int result = 0;
        int up = Math.abs(targetAlphabet[idx]);
        int down = 26 - targetAlphabet[idx];
        result = Math.min(up, down);
        return result;
    }
}

하지만 몇개가 테스트케이스 일치에 실패했고, 반례를 찾았다.

예를 들어 CCCAAAAAAY 의 경우 0번째 인덱스에서 가장 가까운 위치인 왼쪽이나 오른쪽으로 갈 수 있다.

만약 쭉 오른쪽으로 가게 되었을 경우 CCC까지 가고 다시 뒤로 가서 Y로 가게 된다.

C -> C -> C -> C -> C -> C -> Y

반면에 왼쪽으로 가게 되었을 경우 Y까지 가고 다시 앞으로 가서 C로 가게 된다.

C -> Y -> C -> C -> C

즉, 아무리 최소 거리가 왼쪽, 오른쪽 같더라도 어느 방향을 선택함에 따라 결과가 달라지게 되는 것이다.

이를 연속된 A 여부에 따라 조건을 걸었다.

 

 

따라서 다시 문제의 단계를 나누었다.

1. 알파벳을 처음부터 오른쪽 방향으로 순회

2. 하나하나 알파벳을 상, 하 조작으로 알파벳 조작

3. 좌, 우 조직으로 커서 위치 조작


전체 코드이다.

import java.util.*;
class Solution {
    public int solution(String name) {
        int answer = 0;
        int length = name.length();
        
        int move = length-1; //오른쪽으로 쭉 이동했을 때 좌우 이동 거리
        int index; //연속된 A를 세기 위한 변수
        for(int i=0;i<length;i++){
            answer += Math.min(name.charAt(i)-'A', 'Z'- name.charAt(i)+1); //상하 이동
            
            
            index = i+1;
            while(index < length && name.charAt(index) == 'A')index++;
            
            move = Math.min(move, i*2+length-index);
            move = Math.min(move, (length-index)*2 + i);
        }
        return answer + move;
    }
}