programmers.co.kr/learn/courses/30/lessons/12926
문제 설명
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 AB는 1만큼 밀면 BC가 되고, 3만큼 밀면 DE가 됩니다. z는 1만큼 밀면 a가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
제한 조건
- 공백은 아무리 밀어도 공백입니다.
- s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
- s의 길이는 8000이하입니다.
- n은 1 이상, 25이하인 자연수입니다.
입출력 예
s | n | result |
AB | 1 | BC |
z | 1 | a |
a B z | 4 | e F d |
🎈 나의 풀이
def solution(s, n):
answer = ''
u_alphabet=['A',"B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
l_alphabet=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
for i in s:
if i == ' ': # 공백은 그대로 answer에 추가하고 continue
answer+=' '
continue
tf=i.islower() # 문자열 i가 소문자인지 True 또는 False 반환
if tf:
idx=l_alphabet.index(i)+n
else:
idx=u_alphabet.index(i)+n
if idx > 25: # i의 위치에 n을 더한 값 idx가 25보다 크다면 a부터 시작
idx-=26
if tf: # 소문자면 l_alphabet, 대문자면 u_alphabet에 있는 문자를 추가
answer+=l_alphabet[idx]
else:
answer+=u_alphabet[idx]
return answer
대문자와 소문자 각각을 리스트 u_alphabet, l_alphabet에 저장했다.
이 문제 제한조건이 n이 1이상 25이하의 자연수라서 idx-=26이 가능한 것이지 %을 사용하는게 시저 알고리즘에서 일반적이다.
🎨 다른사람 풀이
def solution(s, n):
s = list(s)
for i in range(len(s)):
if s[i].isupper(): # 대문자라면
s[i]=chr((ord(s[i])-ord('A')+ n)%26+ord('A'))
elif s[i].islower(): # 소문자라면
s[i]=chr((ord(s[i])-ord('a')+ n)%26+ord('a'))
return "".join(s) # 리스트를 문자열로
시저 암호 알고리즘을 이용한 풀이.
리스트 s의 길이만큼 반복하면서 대문자인지 소문자인지를 검사한다.
ord함수는 문자의 Unicode를 나타내는 integer를 반환한다. 예를들어 ord('a')는 97이다.
chr함수는 Unicode를 나타내는 integer가 해당하는 문자열을 반환한다.
ord함수와 chr함수는 서로 반대된다.
ord(s[i])-ord('A')는 A로부터 떨어진 s[i]의 거리를 계산하는 것.
영어 알파벳은 총 26개이므로 26으로 나눈 나머지를 이용한다(ex : z에서 1을 더하면 a로 넘어가도록).
def caesar(s, n):
lower_list = "abcdefghijklmnopqrstuvwxyz"
upper_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = []
for i in s:
if i is " ":
result.append(" ")
elif i.islower() is True: # i.islower()도 가능
new_ = lower_list.find(i) + n
result.append(lower_list[new_ % 26])
else:
new_ = upper_list.find(i) + n
result.append(upper_list[new_ % 26])
return "".join(result)
나랑 비슷한 알고리즘.
이걸 보니 내가 힘들게 리스트로 만들었구나ㅠ 그냥 문자열로 해도 되는데
find함수로 i의 위치를 반환한다.(문자열에서 각 문자는 오로지 1개이므로 find를 사용해도 됨)
result를 처음에 리스트로 만들지 않고 문자열로 만들었으면 더 좋았을 것이다.
new를 26으로 나눈 나머지 인덱스 값을 result에 추가한다.
import string
def caesar(s, n):
result = ""
base = ""
for c in s:
if c in string.ascii_lowercase:
base = string.ascii_lowercase
elif c in string.ascii_uppercase:
base = string.ascii_uppercase
else:
result += c # c가 공백이면
continue
a = base.index(c) + n
result += base[a % len(base)]
return result
string.ascii_lowercase는 'abcdefghijklmnopqrstuvwxyz'다.
string.ascii_uppercase는 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'다.
c가 소문자 / 대문자에 따라서 base가 결정된다. 문자열 base에서 c의 위치와 n을 더한 값을 a에 할당한다.
26대신에 base의 길이를 사용하여 a를 나눈 나머지를 구한다.
'coding test' 카테고리의 다른 글
[파이썬] 약수의 합 (0) | 2020.12.24 |
---|---|
[파이썬] 이진 변환 반복하기 (0) | 2020.12.24 |
[파이썬] 내적 (0) | 2020.12.24 |
[파이썬] 문자열을 정수로 바꾸기 (0) | 2020.12.23 |
[파이썬] 숫자의 표현 (0) | 2020.12.23 |