Lv2. 조이스틱 ( Python )
# 문제 설명
조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 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이 다음과 같은 경우에는 간단한 반환이 가능하다.
name이 모두 A로 구성된 경우
# 주어지는 name이 모두 A로 구성되어 있으면 조작이 필요 없으므로 바로 0 반환 if allA == name: return 0
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