Lv2. 조이스틱 ( Python )


Lv2. 조이스틱

# 문제 설명

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

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

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

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

- 첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다.
- 조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다.
- 마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다.
따라서 11번 이동시켜 "JAZ"를 만들 수 있고, 이때가 최소 이동입니다.

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

# 제한 사항

  • name은 알파벳 대문자로만 이루어져 있습니다.
  • name의 길이는 1 이상 20 이하입니다.

# 입출력 예

name return
JEROEN 56
JAN 23


문제 해결 시 고려사항

  • 문자열에 대한 변경 처리 시, 가장 가까운 문자부터 처리

본 문제는 주어지는 A로 구성된 문자를 시작으로 주어지는 name으로 변환할 시 최소 조작 횟수를 반환하는 문제이다. 필자는 name을 가지고 A로 바꾸어 나가는 방법으로 치환하여 문제를 해결하였다.

주어지는 name이 다음과 같은 경우에는 간단한 반환이 가능하다.

  1. name이 모두 A로 구성된 경우

    # 주어지는 name이 모두 A로 구성되어 있으면 조작이 필요 없으므로 바로 0 반환
        if allA == name:
            return 0
    
  2. name이 한 글자인 경우

     # 주어지는 name이 한 글자인 경우 위아래 조작횟수만 증가시키고 반환
        if len(name) == 1:
            return makeDist(name)
    

두 가지 이외의 경우에는 별도의 처리가 필요하다. 이 때 중요한 것은 문자를 변환해 가는 과정 중 현재 인덱스에서 좌,우의 이동 중 가까운 문자로의 이동이 가장 최적이라는 점이다. 그 점에 유의하여 아래와 같이 함수화를 실시하였다.

 # 문자열의 상,하 조작에 대한 조작횟수 반환 함수
 def makeDist(s):
     alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
     idx = alphabet.index(s)
     return min(26-idx, idx)

위와 같이 상,하 조작횟수를 반환하여 주는 makeDist 함수를 구성하였다.

 # A가 아닌 가장 가까운 문자로의 이동을 하며 makeDist를 활용하여 조작횟수 반환
 def makeA(name, allA, ans):
     answer = ans
     nearestIdx, curr, lst = 0, 0, []
     while name != allA:
         leftp, rightp = curr, curr
         #A가 아닌 가장 가까운 인덱스 찾기
         for i in range(len(name)):
             #rightp처리(오른쪽으로 한칸씩)
             rightp += 1
             if rightp > len(name)-1:
                 rightp = 0
             if name[rightp] != 'A':
                 nearestIdx = rightp
                 break
             #leftp처리(왼쪽으로 한칸씩)
             leftp -= 1
             if leftp - i < 0:
                 leftp = len(name)-1 
             if name[leftp] != 'A':
                 nearestIdx = leftp
                 break
         # 현재 위치 기준으로 왼쪽과 오른쪽의 문자 중 더 가까운 문자 위치 찾기
         minVal = min(len(name)+curr-nearestIdx, abs(nearestIdx-curr))
         # 가까중 문자와의 위치 차이와 해당 문자에 대한 A로의 변환 처리
         answer += (minVal+makeDist(name[nearestIdx]))
         # 현재 위치를 해당 문자의 위치로 변경
         curr = nearestIdx
         # 해당 위치 문자를 A로 바꾸고 다시 반복
         name = name[:curr] + 'A' + name[curr+1:]
     return answer

위 두 함수를 이용하여 최종적으로 아래와 같은 과정을 통해 해결하였다.

     # 그 이외의 경우
     else:
         # 주어지는 name에 대해 모든 문자가 A로 바뀌도록 처리
         if name[0] != 'A':
             # 첫 글자에 대한 알파벳 변경 조작 횟수 증가
             answer += makeDist(name[0])
             name = 'A' + name[1:]
         answer = makeA(name,allA,answer)



전체 코드

def makeDist(s):
    alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
    idx = alphabet.index(s)
    return min(26-idx, idx)
def makeA(name, allA, ans):
    answer = ans
    nearestIdx, curr, lst = 0, 0, []
    while name != allA:
        leftp, rightp = curr, curr
        #A가 아닌 가장 가까운 인덱스 찾기
        for i in range(len(name)):
            #rightp처리(오른쪽으로 한칸씩)
            rightp += 1
            if rightp > len(name)-1:
                rightp = 0
            if name[rightp] != 'A':
                nearestIdx = rightp
                break
            #leftp처리(왼쪽으로 한칸씩)
            leftp -= 1
            if leftp - i < 0:
                leftp = len(name)-1 
            if name[leftp] != 'A':
                nearestIdx = leftp
                break
        # 현재 위치 기준으로 왼쪽과 오른쪽의 문자 중 더 가까운 문자 위치 찾기
        minVal = min(len(name)+curr-nearestIdx, abs(nearestIdx-curr))
        # 가까중 문자와의 위치 차이와 해당 문자에 대한 A로의 변환 처리
        answer += (minVal+makeDist(name[nearestIdx]))
        # 현재 위치를 해당 문자의 위치로 변경
        curr = nearestIdx
        # 해당 위치 문자를 A로 바꾸고 다시 반복
        name = name[:curr] + 'A' + name[curr+1:]
    return answer
def solution(name):
    answer = 0
    # 초기 A로만 구성된 문자열 세팅
    allA = ''
    for i in range(len(name)):
        allA += 'A'
    # 주어지는 name이 모두 A로 구성되어 있으면 조작이 필요 없으므로 바로 0 반환
    if allA == name:
        return 0
    # 주어지는 name이 한 글자인 경우 위아래 조작횟수만 증가시키고 반환
    if len(name) == 1:
        return makeDist(name)
    # 그 이외의 경우
    else:
        # 주어지는 name에 대해 모든 문자가 A로 바뀌도록 처리
        if name[0] != 'A':
            # 첫 글자에 대한 알파벳 변경 조작 횟수 증가
            answer += makeDist(name[0])
            name = 'A' + name[1:]
        answer = makeA(name,allA,answer)
    return answer