데이터분석 기록일지

문제풀이/프로그래머스

[프로그래머스 Lv.1] 시저 암호 (Python)

야하루 2024. 8. 15. 23:37

코딩테스트 연습 - 시저 암호 | 프로그래머스 스쿨 (programmers.co.kr)

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제

어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "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"

 

 

 

 


풀이

아이디어:  대문자, 소문자 리스트를 만들고 s의 문자가 리스트에서 위치하는 인덱스를 찾아 n을 더한다.
합이 25가 넘는다면 1바퀴를 돌기 때문에 26을 빼준다.
def solution(s, n):
    uppercase = ['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'] 
    lowercase = ['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']
    answer = []
    for i in s:
        if i == " ":
            answer.append(i)
        elif i == i.lower():
            num = lowercase.index(i)
            if num+n > 25:
                i = lowercase[num+n-26]
                answer.append(i)
            else:  
                i = lowercase[num+n]
                answer.append(i)
        else:
            num = uppercase.index(i)
            if num+n > 25:
                i = uppercase[num+n-26]
                answer.append(i)
            else:
                i = uppercase[num+n]
                answer.append(i)
    return "".join(answer)

-> 나머지 활용할 줄도 몰랐어서 그냥 아주 긴 비효율적 풀이이다

 

 

 


다른 풀이 모음

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:
            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)

이게 내가 짜고 싶었던 코드..

소문자 or 대문자와 동일하다 대신에 islower(), isupper() 같은 함수를 사용해서 바로 T/F 반환하기.

여기서는 리스트 대신에 문자열을 사용해 주었고, 그래서 index() 대신 find() 메소드를 이용했다.

또한 조건을 걸어서 26을 빼고 계속 더해주는게 아니라, 26으로 나눴을 때 나머지를 이용해서 한번에 작성 가능.

 

 

 

def caesar(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)

유니코드를 이용해서 푼 방법이다.

ord(s[i]) - ord('A')는 특정 문자의 유니코드에서 'A'의 코드를 뺌으로써, A를 기준으로 한 상대적인 위치를 계산한다.

그 상대적인 위치에 n을 더하고 26으로 나눈 나머지를 구해서, A를 기준으로 얼만큼 밀어야 하는지 계산한다.

그리고 다시 빼준 A의 유니코드 문자를 더해준 다음에, 문자로 변환하여 암호화를 수행

 

 

 

ord() 함수
문자를 인자로 받아서 해당 문자에 해당하는 유니코드 정수를 반환한다.

chr() 함수
유니코드 정수를 인자로 받아서 해당 정수에 해당하는 문자를 반환해준다.

유니코드 코드 포인트 :
유니코드에서 각 문자에 할당된 고유한 정수 값
각 문자는 컴퓨터 메모리에 저장될 때 특정한 정수 값으로 변환되어 처리되는데,
이 정수 값이 바로 유니코드 코드 포인트