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

seulzzang·2022년 9월 22일
0

코딩테스트 연습

목록 보기
17/44
post-thumbnail

📍문제

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

📍풀이

  • 아스키코드값으로 접근

  • z, Z인 경우 1만큼 밀면 a, A가 되므로 조건문 달아주고, 공백은 아무리 밀어도 공백이니까 조건문에서 그냥 pass, 그 외의 경우 아스키코드값에 그냥 +n해주는 방식으로 코드를 짰다.

💻첫번째 코드 (오답)

def solution(s, n):
    answer = ''
    # A=65 Z=90 a=97 z=122 공백=32
    s = list(s)
    ord_list = []
    for i in s:
        ord_list.append(ord(i))
        to_chr_list = [] # 다시 알파벳으로 바꿔야하는 아스키코드값 리스트
        for ordnum in ord_list:
            if ordnum == 90 or ordnum == 122: # z나 Z인 경우
                ordnum += -26 +n 
                # ordnum -= 26-n
            elif ordnum == 32: # 공백은 아무리 밀어도 공백
                pass
            else: # 보통의 경우 그냥 +n
                ordnum += n
            to_chr_list.append(ordnum)
    for to_chr in to_chr_list:
        new_alpha = chr(to_chr)
        answer += new_alpha
    return answer

이렇게 작성하면 코드실행시 나오는 테스트케이스 3개는 통과하는데 채점을 하면 테스트 9빼고 모조리 실패로 뜸.. 그래서 질문하기 탭에서 다른 사람들이 질문하고 알려준 풀이를 좀 봤는데 내가 Z의 경우만 생각했다는걸 깨달음..!!
y에서 2만큼 밀면 또 a가 나옴.. 이런 경우의 수를 생각해야함..
n은 1 이상 25 이하이다!

💻두번째 코드 (오답)

def solution(s, n):
    answer = ''
    # A=65 Z=90 a=97 z=122 공백=32
    # 대문자 65~90 소문자 97~122
    s = list(s)
    ord_list = []
    for i in s:
        ord_list.append(ord(i))
        to_chr_list = [] # 다시 알파벳으로 바꿔야하는 아스키코드값 리스트
        for ordnum in ord_list:
            if ordnum == 32:
                pass
            elif 65 <= ordnum+n <= 90 or 97 <= ordnum+n <= 122:
                ordnum += n
            else:
                ordnum += (n-26)
            to_chr_list.append(ordnum)
    for to_chr in to_chr_list:
        new_alpha = chr(to_chr)
        answer += new_alpha
    return answer

ord_num에서 n을 더했을때 소문자 범위와 대문자 범위 안에 있다면 Z에서 1을 더했을때 A로 넘어가는것 같은 일이 없다는 것이니 그냥 ord_num += n을 해주고 그렇지 않으면 ordnum += (n-26)을 해주는 방식으로 했다.. 이러면 y에서 2만큼 밀면 a가 나오는 것과 같은.. 이런것도 다 해결해주리라 믿었다.


근데 또 생각하다보니 대문자와 소문자의 범위가 겹치는..게..
n이 25일 경우를 생각해보자면요?
Y(89)에서 +25를 해주면 114가 나오는데 이때 -26을 해줘야 정상적인 값이 나오거든요? 근데 이제 11497 <= ordnum+n <= 122이 조건문에 걸려서 그냥 +25만 해주는 불상사가 생기게 됨요.. (그래서 엉뚱한 소문자 값이 나오게 되는 것)
그렇다면 아예 문자가 대문자일 경우 대문자에서만 놀도록, 소문자일 경우 소문자에서만 놀도록 다시 코드를 짜보기로 했다.

💻세번째 풀이 (정!!답!!!!!!!!)

  1. (ordnum-65+n)%26 를 하면 대문자에서 몇번째의 값인지를 반환해줌
  2. 대문자의 경우 65(A)부터 아스키코드값이 시작하니까 +65를 해준다. (몇번째 대문자인지의 그 수가 필요한게 아니라 그거에 해당하는 아스키값이 필요한 것이기 때문에 +65)
  3. 마찬가지로 소문자의 경우 97(a)부터 시작하니까 65자리에 97을 넣어주면 됨
def solution(s, n):
    answer = ''
    # A=65 Z=90 a=97 z=122 공백=32
    # 대문자 65~90 소문자 97~122
    s = list(s)
    ord_list = []
    for i in s:
        ord_list.append(ord(i))
        to_chr_list = [] # 다시 알파벳으로 바꿔야하는 아스키코드값 리스트
        for ordnum in ord_list:
            if ordnum == 32:
                pass
            # 대문자인 경우
            elif 65 <= ordnum <= 90:
                ordnum = (ordnum-65+n)%26 + 65
            # 소문자인 경우
            elif 97 <= ordnum+n <= 122:
                ordnum = (ordnum-97+n)%26 + 97
            else:
                ordnum += (n-26)
            to_chr_list.append(ordnum)
    for to_chr in to_chr_list:
        new_alpha = chr(to_chr)
        answer += new_alpha
    return answer

그러면 드디어 통과를 하게되는 것이다..

📍다른사람 풀이

1. 아스키 코드사용

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)

내 과정을 이렇게 간략하게 표현할 수가.. 있답니다?
나는 chr(ord(i))이런식으로 함수 중첩해서 쓰면 어떤값이 나오는지 아직 헷갈려서.. 저렇게 일일이 다 풀어썼당.. 그래도 내 풀이가 더 직관적으로 이해가 된다고..위안을 삼아본다..

2. 문자열 풀이

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)

대문자, 소문자를 다 문자열로 두고 s안에 있는 문자들을 조건문 돌리는 방법.. 만약에 소문자라면 lower_list에서 해당 문자가 있는 인덱스를 찾아주고(.find(i)) 그 인덱스 번호에 +n한 인덱스 번호에 해당하는 알파벳을 append해주는 방식인듯! 이게 더 간단해 보이기도 하고...?


개인적으로 테스트케이스가 헷갈릴만한거를 하나 더 알려줬으면 사람들이 덜헤매지 않을까..라는 생각이!

profile
중요한 것은 꺾이지 않는 마음

0개의 댓글