프로그래머스 Level2 : 조이스틱

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA

조이스틱을 각 방향으로 움직이면 아래와 같습니다.

  • ▲ - 다음 알파벳
  • ▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로)
  • ◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서)
  • ▶ - 커서를 오른쪽으로 이동

예를 들어 아래의 방법으로 JAZ를 만들 수 있습니다.

  1. 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다.
  2. 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다.
  3. 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다.

따라서 11번 이동시켜 “JAZ”를 만들 수 있고, 이때가 최소 이동입니다.

만들고자 하는 이름 name이 매개변수로 주어질 때, 이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.

제한 사항
  • name은 알파벳 대문자로만 이루어져 있습니다.
  • name의 길이는 1 이상 20 이하입니다.
입출력 예
name return
“JEROEN” 56
“JAN” 23

해설

오후 5시부터 5시간은 고민했다. char_to_numname을 각 문자가 A가 되기 위해서 움직여야하는 조이스틱 수로 바꿔준다. 여기선 아스키코드를 이용했다. cursor는 조이스틱의 위치를 나타내고, 이를 이용해 조이스틱 위치에서 좌 우로 움직일때 최종 결과가 더 작은 값이 되도록 재귀함수로 구현했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def solution(name): 
    char_to_num = [min(ord(val)-ord("A"), ord("Z")-ord(val)+1) for val in name]
    answer = min(greedy(0, char_to_num, 1, 0), greedy(0, char_to_num, -1, 0))
    return answer

def greedy(cursor, char_to_num, change, total):
    char_to_num = char_to_num.copy()
    if total > len(char_to_num):
    #worstcase의 함수 호출 횟수는 name의 길이
        return 26*len(char_to_num) 
    #무의미한 동작은 worstcase가 나오도록 해준다. Ex)"AAAB"
    elif set(char_to_num) == {0}: #모든 문자가 변환되면 종료
        return -1 
    if cursor < 0:
        cursor = len(char_to_num) - abs(cursor)%len(char_to_num)
    elif cursor >= len(char_to_num):
        cursor -= len(char_to_num)
    val = char_to_num[cursor] + 1 #항상 1을 더하므로 마지막 호출시 1을 빼준다.
    char_to_num[cursor] = 0 #커서 위치의 문자를 변환함을 의미한다.
    cursor += change #오른쪽/왼쪽 이동을 결정
    total += 1 #함수 호출 횟수를 결정
    return val + min(greedy(cursor, char_to_num, 1, total), greedy(cursor, char_to_num, -1, total))

다른사람 풀이를 봤는데 테스트 11이 추가되기 전 풀이가 많아서 참고할 만한 것은 발견하지 못했다. AABAAAAAAABBB는 답이 11인데, 14로 출력되는 코드로 테스트해도 통과된다는 글도 발견했는데, 아직 테스트 케이스가 모자란 것 같다.

Leave a comment