🧩 Algorithm/프로그래머스

[programmers] 시저 암호, 신고 결과 받기, 개인정보 수집 유효기간

nerowiki 2024. 4. 15. 22:58
728x90
💡 오늘의 학습 키워드
- 시저 암호
- 신고 결과 받기
- 개인정보 수집 유효기간

 

🥉 시저 암호

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/12926

 

문제 설명

더보기
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다.
예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다.
문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
제한 조건
1. 공백은 아무리 밀어도 공백입니다.
2. s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
3. s의 길이는 8000이하입니다.
4. n은 1 이상, 25이하인 자연수입니다.

 

문제 회고

💡 어떤 문제가 있었고, 나는 어떤 시도를 했는지 그리고 새롭게 안 사실은 무엇인지

ASCII 코드 값에서 해당하는 숫자로 변환하는 함수를 알고 있으면 반복문 하나로 해결할 수 있습니다.

isupper( ) 와 islower( ) 함수로 문자열의 대, 소문자 상태를 True, False로 리턴받을 수 있습니다.
ord( ) 함수는 아스키 코드의 숫자 값으로 변환해주고, chr( ) 함수는 숫자를 해당 아스키 코드 문자로 변환합니다.

이 함수들을 활용하면 특정 위치의 문자에서 원하는 위치의 문자로 이동하는 로직을 구현할 수 있습니다.
그리고 값 사이 범위를 순환할 수 있도록 아래 코드와 같은 로직으로 간결하게 구현할 수 있습니다.

 

💡 내가 해결한 방식은?
def solution(s, n):
    answer = ''
    # "각" 알파벳을 일정 거리만큼 밀기
    for word in s:
        # 대문자 암호 변환
        if word.isupper():
            answer += chr(((ord(word)-ord("A") + n) % 26) + ord("A"))
        # 소문자 암호 변환
        elif word.islower():
            answer += chr(((ord(word)-ord("a") + n) % 26) + ord("a"))
        # 공백 처리
        elif word == " ":
            answer += " "
        
    return answer

 

 


🥈 신고 결과 받기

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/92334

 

문제 설명

💡 어떤 문제가 있었고, 나는 어떤 시도를 했는지 그리고 새롭게 안 사실은 무엇인지

문제에서 요구하는 풀이 과정이 명확하게 드러나 구현 능력과 시간만 있다면 충분히 도전할 만한 문제였습니다.
문제 해결 과정은 크게 다음과 같습니다.

  1. 신고 리스트를 순회하면서 중복 없는 신고 리스트를 생성합니다.
  2. 신고 당한 유저의 신고 당한 횟수를 저장합니다.
  3. k회 이상 신고로 정지 당한 유저를 통해 해당 유저를 신고한 유저가 받은 메일 횟수를 리턴합니다.

첫 번째 풀이도 결과 값은 동일하게 출력되지만 다음 방법으로 가독성과 효율성을 포함한 코드로 개선할 수 있습니다.

먼저, 딕셔너리를 반복문 없이 다음과 같이 초기화 하는 것입니다. 

report_list = { id: 0 for id in id_list }

 

그리고 report 리스트를 순회하며 공백을 기준으로 split 하는데 아래와 같이 하나의 리스트에 넣을 수도 있지만, 

user_list = rt.split(" ")

다음과 같이 표현하면 불필요한 리스트 생성 없이 각각의 값들을 좀 더 직관적으로 사용할 수 있습니다.

reporter, reported = rp.split(" ")

이렇게 splite 한 값을 변수 2개로 활용하면 reverse_list 같은 불필요한 방법 없이 코드가 간결하게 개선됩니다.

 

딕셔너리의 value 값들은 다음 코드로 반복문 없이 한꺼번에 리턴할 수 있습니다.

list(email_list.values())

 

결과도 중요하지만 두 번째 코드와 같이 주어진 함수와 자료구조를 잘 활용하여 풀 수 있어야 합니다. 

 

💡 내가 해결한 방식은?
자료구조와 로직에 대한 이해 + c++ 스타일 풀이
def solution(id_list, report, k):
    user_report = set()   	# 중복 없는 신고 set 객체
    user_list= []       	# 신고한 유저와 신고 당한 유저 리스트 
    reverse_list = []		# 신고한 유저 리스트
    
    report_list = {}    	# 신고 누적 딕셔너리 
    email_list = {}     	# 이메일 전송 딕셔너리  
  
    
    # 딕셔너리 유저 등록 및 초기화
    for id in id_list:
        report_list[id] = 0
        email_list[id] = 0
        
    # 정지 당한 유저 구하기
    # report "이용자ID 신고한ID" 순회
    for rt in report:
        # 중복 방지
        if rt in user_report:
            continue
        # rt 값이 없을 경우 user_report 리스트에 추가
        user_report.add(rt)
        
        # report 리스트를 이용자ID, 신고ID로 나누어 저장
        user_list = rt.split(" ")
        reverse_list.append(user_list[::-1])
        
        # 신고 누적 딕셔너리에 해당 신고 당한 유저 있을 경우
        if user_list[1] in report_list:
            report_list[user_list[1]] += 1
        
    # 신고 누적 딕셔너리 순회
    for rl in report_list:
        # 신고 누적 값이 K 이상일 경우
        if report_list[rl] >= k:
            # 신고한 유저 구하는 리스트 순회
            for revl in reverse_list:
                # 신고 당한 유저일 경우
                if revl[0] == rl: 
                    # 해당 리스트에서 신고한 유저 메일 전송
                    email_list[revl[1]] += 1

    
    return [email_list[el] for el in email_list]
자료구조와 로직에 대한 이해 + python 스타일 풀이
def solution(id_list, report, k):
    user_report = set()                         # 중복 없는 신고 리스트
    
    report_list = {id: 0 for id in id_list}     # 신고 누적 리스트 id_list로 초기화 
    email_list = {id: 0 for id in id_list}
    
    # report 리스트 순회하면서, 중복 없는 신고 리스트 생성
    for rp in report:
        # 신고한 사람과 신고 당한 사람 따로 저장
        reporter, reported = rp.split(" ")
        
        # 위 값들이 중복 없는 신고 리스트에 없는 경우
        if (reporter, reported) not in user_report:
            user_report.add((reporter, reported))   # set 객체 안에 튜플로 저장
            report_list[reported] += 1              # 신고 당한 사람 신고 횟수 누적
            
    # K회 이상 신고로 정지 당한 사람 ID 리스트
    banned_list = [id for id in id_list if report_list[id] >= k]
    
    # 중복 없는 리스트를 순회하며 각 유저 별 메일 전송 횟수 계산
    for reporter, reported in user_report:
        # 정지 당한 사람 ID 리스트 안에 중복 없는 신고 리스트 값이 있다면
        if reported in banned_list:
            # 신고한 사람의 이메일 전송 횟수 누적
            email_list[reporter] += 1
            
    
    return list(email_list.values())

 


🥇 개인정보 수집 유효기간

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/150370

 

문제 설명

💡 어떤 문제가 있었고, 나는 어떤 시도를 했는지 그리고 새롭게 안 사실은 무엇인지

 

💡 내가 해결한 방식은?

 


✍️ TIL

알아야 하는 함수는 빠르게 학습하고 적용하고 있다. isupper, islower, chr, ord 함수를 모르고 문제에 접근했다면
문제 푸는데 많은 시간을 소모했을 것이다. 로직도 생각보다 간단하게 떠오르지 않았지만 일정한 값을 순회할 때
% 연산이 필수라는 것만 기억하자

 

두 번째 문제는 문제에서 바라는 풀이 과정이 일련의 표와 함께 명확하게 제시되어
풀이 아이디어는 빠르게 그려냈지만,
딕셔너리를 능숙하게 활용하지 못했다ㅠ
split 한 값을 두 개의 변수에 넣고 풀어내는 방식도 알고 있었다면 더 빠르게 풀어냈을 것 같다.
여러모로 부족한 코드를 제출하게 되어 아쉬웠지만 파이썬에서의 장점을 살릴 수 있는
코드 스타일을 학습할 수 있었던 걸로 만족하고 있다.