Slow is better than NOTHING

Programmers 풀이/[KaKao]

[Python] 프로그래머스 2022 KAKAO 코딩테스트 - 신고 결과 받기

Jeff_Kang 2022. 1. 31. 17:26
반응형

문제 설명

신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.

  • 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
    • 신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다.
    • 한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다.
  • k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
    • 유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.

다음은 전체 유저 목록이 ["muzi", "frodo", "apeach", "neo"]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다.

각 유저별로 신고당한 횟수

K=2 일 경우, 2번이상 신고당한 "Frodo"와 "neo"는 게시판 이용이 정지됩니다.

따라서 "muzi"는 처리 결과 메일을 2회, "frodo"와 "apeach"는 각각 처리 결과 메일을 1회 받게 됩니다.

이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.


주어진 입력 값으로 부터 숨겨진 상관관계를 이해하고 추상화된 개념을 코드로 만들어낼 수 있는지에 대한 Level 1 문제입니다. 이 문제에서 신경쓸만한 점은 딱히 없었으며, 성능 향상을 위해 최적화 정도는 생각해볼 수 있겠지만 저는 머릿속에서 생각해본 추상화된 Logic을 코드로 옮겨보는 연습차 풀어보았습니다. 따라서, 접근 방법 및 코드가 100점짜리 코드라고 할 수 는 없음을 미리 알려드리며 참고용으로만 보시기 바랍니다..!!

Logic

1. 전체 유저 목록 'id_list' 와 신고한 목록 'report' 가 주어졌을 때, 각 id별 신고한 정보를 Tracking할 수 있는 자료구조를 정의하고 초기화한다.

2. K값을 기준으로 게시판 이용이 정지되는 유저를 1번 로직에서 얻은 자료구조로부터 구한다.

3. 3번으로 부터 구해진 게시판 이용 정지 유저를 1번에서 만든 자료구조를 통해 각 유저별 처리 결과 메일을 받은 횟수를 구한다.

Solution

  • 1번 로직

주어진 전체 유저 목록 'id_list' 와 신고한 목록 'report' 로 부터, 문제에서 요구하는 정보를 저장하고 계산하기 위해 python의 'defaultdict' 구조를 활용하였습니다.

report 된 정보를 parsing하여 초기화된 defaultdict 자료구조에 정보를 입력합니다. 
user_stack 에는 user 별 report한 user list를 담고, number_of_reported 에는 user 별 report된 횟수를 입력합니다.
단, 제한조건에서 중복된 신고는 1개로 생각한다고 했으므로 'set' 자료형을 이용해 중복된 신고 리스트를 없애줍니다.

# defaultdict 선언
number_of_reported = defaultdict(int)
user_stack = defaultdict(list)

# defaultdict 초기화
[user_stack[id] for id in id_list]
[number_of_reported[id] for id in id_list]

# output
# defaultdict(<class 'list'>, {'muzi': [], 'frodo': [], 'apeach': [], 'neo': []})
# defaultdict(<class 'int'>, {'muzi': 0, 'frodo': 0, 'apeach': 0, 'neo': 0})

for line in set(report):
    user_id, reported_id = line.split()
    user_stack[user_id].append(reported_id)
    number_of_reported[reported_id] += 1
    
# output
# defaultdict(<class 'list'>, {'muzi': ['neo', 'frodo'], 'frodo': ['neo'], 'apeach': ['muzi', 'frodo'], 'neo': []})
# defaultdict(<class 'int'>, {'muzi': 1, 'frodo': 2, 'apeach': 0, 'neo': 2})
  • 2번 로직

'report' 입력 값을 통해 구해진 'number_of_reported' 로 부터 K 값을 이용해 게시판 이용이 정지당한 유저를 알아낼 수 있습니다.
report된 횟수(val)이 정해진 Threshold 'K'보다 크거나 같다면 이용이 정지되므로, 해당 유저(id) 만 추출해냅니다.

blocked_user = [id for id, val in number_of_reported.items() if val >=k]
# output
# ['frodo', 'neo']
  • 3번 로직

3번 로직에서 구해진 정지된 유저들을 기준으로 user 별 report 내용 중 메일로 회신이 가능한지 여부를 확인합니다.

for id, val in user_stack.items():
    count = 0 
    for black_user in blocked_user:
        if black_user in val:
            count += 1
    answer.append(count)

 

전체 코드

더보기
from collections import defaultdict

def solution(id_list, report, k):
    answer = []
    number_of_reported = defaultdict(int)
    user_stack = defaultdict(list)

    [user_stack[id] for id in id_list]
    [number_of_reported[id] for id in id_list]
    
    for line in set(report):
        user_id, reported_id = line.split()
        user_stack[user_id].append(reported_id)
        number_of_reported[reported_id] += 1
    
    blocked_user = [id for id, val in number_of_reported.items() if val >=k]
    for id, val in user_stack.items():
        count = 0 
        for black_user in blocked_user:
            if black_user in val:
                count += 1
        answer.append(count)
                
    return answer
반응형