본문 바로가기
알고리즘/문제풀이

조이스틱(프로그래머스, Lv2, Java)

by 모스키토끼 2020. 3. 1.

1. 조이스틱

문제링크: https://programmers.co.kr/learn/courses/30/lessons/42860

 

코딩테스트 연습 - 조이스틱 | 프로그래머스

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA 조이스틱을 각 방향으로 움직이면 아래와 같습니다. ▲ - 다음 알파벳 ▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로) ◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서) ▶ - 커서를 오른쪽으로 이동 예를 들어 아래의 방법으로 JAZ를 만들 수 있습니다. - 첫 번째 위

programmers.co.kr

알고리즘 설명:

탐욕법으로 당장 가장 가까운 A가 아닌 값으로만 탐색해 나가면 된다.

  • 현재 인덱스에서 좌우로 탐색을 진행하여 A가 아닌 값이 먼저 나온 곳으로 인덱스를 옮겨서 탐색을 진행한다.
  • A가 아닌 경우를 찾으면 문자열을 A로 바꾸고 다시 탐색 되지 않도록 한다.
  • 문자열 값 변경이 일어나지 않은 경우 => 전부 탐색된 경우(전부 A로 바꾸었기 때문) -> while문 스톱
    flag 변수를 하나 만들어 문자열을 변경하는 경우와 아닌 경우를 구분한다.
  • 알파벳 개수 26의 반절인 13을 기준으로 그 밑에 알파벳이면 위로 아니면 아래로 카운팅을 해준다.
  • 왼쪽에서 오른쪽으로 탐색하는 코드를 오른쪽에서 왼쪽으로 탐색하는 코드보다 먼저 두어 우선으로 탐색한다.

막혔던 지점:

  • BBBAAAB와 같이 A가 아닌 값이 나왔다고 바로 인덱스를 옮기는 것이 아니라 전체적으로 A가 아닌 문자를 탐색해서 경로를 결정해야 하는 경우가 있는데, 이 경우는 탐욕법에서 벗어나기 때문에 무시하였다.
    -> 프로그래머스 통과

코드(Java)

package coding;

public class Joystick {
	public static int solution(String name) {
		char[] word = name.toCharArray();
		int answer = 0;
		int len = word.length;
		int nowIdx =0;
		boolean flag = true; // 변경이 있는 지 확인하는 플래그
		
		//변경이 없을 때 까지
		while(flag) {
			//왼쪽에서 오른쪽으로 가는 인덱스
			int leftToright = 0;
			//오른쪽에서 왼쪽으로 가는 인덱스
			int rightToleft = 0;
			
			//플래그 초기화
			flag = false;
			
			//A인 경우가 아닌 인덱스를 탐색
			for(int i=0;i<len;i++) {
				
				//인덱스가 범위를 넘어가지 않았을 때
				if(nowIdx+i<len)
					leftToright = nowIdx +i;
				//인덱스가 범위를 넘어갔을 때
				else
					leftToright = nowIdx +i - len;
				
				if(nowIdx-i>=0)
					rightToleft = nowIdx -i;
				else
					rightToleft = nowIdx -i + len;
				
				if(word[leftToright]!='A') {
					//i는 오른쪽으로 움직인 횟수이므로 answer에 더해줌
					answer += i;
					//위로 움직일지 아래로 움직일지
					if(word[leftToright]-'A'>13) answer += 26-(word[leftToright]-'A');
					else answer += word[leftToright] - 'A';
					//값을 A로 바꾸어주어 다시 탐색되는 경우가 없도록 한다.
					word[leftToright] = 'A';
					nowIdx = leftToright;
					//A가 아닌 경우가 존재하면 변화가 있는 것이므로 flag를 true로 바꾸어주어 변화가 있다고 알려줌
					flag =true;
					break;
				}else if(word[rightToleft]!='A') {
					//i는 왼쪽으로 움직인 횟수이므로 answer에 더해줌
					answer += i;
					if(word[rightToleft]-'A'>13) answer += 26-(word[rightToleft]-'A');
					else answer += word[rightToleft] - 'A';
					word[rightToleft] = 'A';
					nowIdx = rightToleft;
					flag = true;
					break;
				}
				
			}
			
		}
		return answer;
	}

	public static void main(String[] args) {
		System.out.println(solution("JAN"));
	}

}

댓글