Python/Algorithm

문자열 - 다이얼

noodle-dev 2020. 3. 12. 16:11

문제

상근이의 할머니는 아래 그림과 같이 오래된 다이얼 전화기를 사용한다.

img

전화를 걸고 싶은 번호가 있다면, 숫자를 하나를 누른 다음에 금속 핀이 있는 곳 까지 시계방향으로 돌려야 한다. 숫자를 하나 누르면 다이얼이 처음 위치로 돌아가고, 다음 숫자를 누르려면 다이얼을 처음 위치에서 다시 돌려야 한다.

숫자 1을 걸려면 총 2초가 필요하다. 1보다 큰 수를 거는데 걸리는 시간은 이보다 더 걸리며, 한 칸 옆에 있는 숫자를 걸기 위해선 1초씩 더 걸린다.

상근이의 할머니는 전화 번호를 각 숫자에 해당하는 문자로 외운다. 즉, 어떤 단어를 걸 때, 각 알파벳에 해당하는 숫자를 걸면 된다. 예를 들어, UNUCIC는 868242와 같다.

할머니가 외운 단어가 주어졌을 때, 이 전화를 걸기 위해서 필요한 시간을 구하는 프로그램을 작성하시오.

정리>> A,B,C:3회, D,E,F:3회, ...

입력

첫째 줄에 알파벳 대문자로 이루어진 단어가 주어진다. 단어는 2글자~15글자로 이루어져 있다.

출력

첫째 줄에 다이얼을 걸기 위해서 필요한 시간을 출력한다.

 

문제출처: https://www.acmicpc.net/problem/5622

풀이 과정

.

.

.

.

.

.

.

.

.

.

#1. Dictionary

  • alphabet과 dial을 매칭한 dictionary를 생성한다.
  • list+=list 보다 list.extend(list) 성능이 더 좋다.

 

Alphabet list

alpha=list(map(chr,list(range(ord('A'),ord('Z')+1))))
#or
alpha = list(map(chr, range(65, 91)))

 

갯수 리스트 만들기

  • 방법1. 다이얼을 정해진 갯수만큼 직접 추가
d=[]
for i in range(3,8):d.extend([i]*3)
d.extend([8]*4+[9]*3+[10]*4)
print(d)
#[2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9]
  • 방법2. 다이얼과 갯수를 dictionary로 만들어 합치기
alpha = list(map(chr, range(65, 91)))
d=[]
splt={2:3,3:3,4:3,5:3,6:3,7:4,8:3,9:4}
for dial,n in splt.items():
    d.extend([dial]*n)
print(d)
#[2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9]
  • 방법3. 위와같다.
nums=[3,3,3,3,3,4,3,4]
d=[]
for idx, dial in enumerate(range(2,10)):
    d.extend([dial]*nums[idx])
print(d)
#[2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9]

 

알파벳 리스트와 갯수 리스트를 dictionarify

alpha = list(map(chr, range(65, 91)))

dict(zip(alpha,d))
#or
{a:b for a,b in zip(alpha,d) }

#{'A': 3,
 'B': 3,
 'C': 3,

 

완성

txt=input()
alpha = list(map(chr, range(65, 91)))

nums=[3,3,3,3,3,4,3,4]
d=[]
for idx, dial in enumerate(range(2,10)):
    d.extend([dial]*nums[idx])

dial=dict(zip(alpha,d))
print(sum([dial[i]+1 for i in txt]))

 

#2. 나눗셈의 몫

  • step(여기서는 3)으로 나눈 몫을 이용하여 (ord(s)-65)//3 +3 으로 앞에서 3개씩 나누어 3,4,... 으로 반환 가능하다.
  • SVYZ인 이유는 앞에서부터 3으로 나눴을 때 한칸씩 밀리는 알파벳들이다.
x=input()
print(sum((ord(s)-65)//3+3 for s in x)-sum(x.count(s) for s in 'SVYZ'))

예를 들어 ord('A') 값은 65이다. A,B,Cord함수 적용하여 65를 빼면 0,1,2이며, 3으로 나눈 몫은 0이다. 이에 3을 더하면 A,B,C3,3,3을 반환한다.

연속적인 수열//step+initial 와 같이 몫을 이용하면 step별로 규칙적인 수를 반환할 수 있다. 몫은 step 구간 개념으로 이용 가능하다.

SVYZ를 따로 계산한 이유는, 알파벳을 처음부터 3개씩 나눴을 때, 문제에서 주어진 구간과 달라지는 알파벳들이 S,V,Y,Z이다. 이들을 각각 한 단계씩 앞으로 보내면 문제에서 주어지는 알파벳 그룹과 같게 된다.