[프로그래머스/파이썬] 신고 결과 받기
참고
과정이 세세히 적혀있고 생각했던 풀이의 연장선이라 감사히 참고하였다.
문제
https://programmers.co.kr/learn/courses/30/lessons/92334
코딩테스트 연습 - 신고 결과 받기
문제 설명 신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다. 각 유저는 한 번에 한 명의
programmers.co.kr
소스코드
from collections import defaultdict
def solution(id_list, report, k):
answer = [0]*len(id_list)
report = set(report)
user_id_who_i_report = defaultdict(set) # value 형태가 set
num_of_reported = defaultdict(int) # value 형태가 int
suspended = [] # k 이상인 id
for r in report:
do_report, be_reported = r.split()
num_of_reported[be_reported] += 1
user_id_who_i_report[do_report].add(be_reported) # dict에 value 값 추가
if num_of_reported[be_reported] == k:
suspended.append(be_reported)
for s in suspended:
for i in range(len(id_list)):
if s in user_id_who_i_report[id_list[i]]:
anwer[i] += 1
return answer
풀이
Dictionary, defaultdict
dictionary 자료구조를 사용해야 겠다는 생각은 했다. dictionary 2개를 이용해서 유저별 신고한 유저 정보를 담은 사전 1개, 유저별 나를 신고한 사람 정보를 사전 1개.
하지만 값이 들어가 있지 않은 dictionary는 어떻게 정의해야 할지 몰랐고, 주어지는 값들을 원하는 형태로 만드는 법도 몰랐다. dictionary에 대한 개념 부족 + defaultdict 개념을 몰랐기 때문이다.
보통 dictionary를 사용하는 문제에서는 defaultdict를 사용한다고 한다. collection 라이브러리에서 defaultdict를 import 한다. 알아두자 알아두자.
from collections import defaultdict
그래서 사용할 2개의 dictionary를 key:value 형태로 다시 정리하자면
- 신고를 행한 유저 A (string) : 유저 A가 신고한 유저 목록 (set) --> dictionary 명: user_list_who_i_report
- 신고를 당한 유저 A (string) : 유저 A를 신고한 유저 수 (int) --> dictionary 명: num_of_reported
사실 처음에는 "유저 A를 신고한 유저"를 int형으로 나타낼 생각을 하지 못했다. 이것 또한 string 형태로 넣으려고 했지. 문제에서 구하라는 형태대로 값을 바로 생성하도록 하자.
문제조건 및 제한사항
각 유저는 한 번에 한 명의 유저를 신고할 수 있다. 한 유저가 여러 번 신고할 수도 있지만 동일한 유저에 대한 신고 횟수는 1회로 처리된다는 것이다. 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report 을 set( ) 으로 묶어 중복값 제거가 필요했다.
k번 이상 신고된 유저는 게시판 이용이 정지된다. 그러면.. k번 이상 신고당한 유저의 목록을 따로 만들어 주어야 한다. 이 리스트를 만들 생각도 못 했는데... 알고리즘 문제를 풀면서의 중간 과정을 변수나 배열 형태로 저장해야 한다는 거를 꼭 기억해서 실천해야 겠다.
참고한 자료에서는 suspended 라는 리스트를 만들어줬다.
그리고 해당 유저를 신고한 모든 유저들에게 정지 사실을 메일로 발송한다. 그 때 각 유저별로 받은 결과 메일 수를 담고 리턴한다. 메일 수를 담은 리스트는 id_list에 기입된 ID와 동일한 순서로 리턴해야 한다.
이를 위해 id_list의 len만큼 answer 배열을 [0, 0, 0, 0] 형태로 초기화시켰다.
해결
주어진 리스트 report에 들어 있는 값은 "신고하는 사람 신고당하는 사람" 형태로 되어 있다. 각 데이터를 split() 함수를 이용하여 공백을 기준으로 나눠주고, 신고한 사람을 do_report로, 신고당한 사람을 be_reported로 정의하여 값을 얻는다.
이 상태에서 반복문 및 조건문을 이용하여 위에 정의한 두 딕셔너리를 채워주고, 채움과 동시에 k번 이상 신고당해 게시판 이용이 정지된 유저도 걸러낼 수 있었다.
num_of_reported 사전에 유저 별 신고당한 횟수를 기록할 때, 신고당해서 1을 더하여 k가 된다면 몇 번 더 신고당하던지 정지 대상자이므로 suspended에 담아주면 된다.
마지막으로 각 유저들이 신고한 내용(사람)이 담겨있는 딕셔너리(user_list_who_i_report)와 id_list를 이용하여 suspended에 속한 유저들이 user_list_who_i_report[id_list[i]]에 포함되어 있다면 answer에서 해당되는 자리 (반복문 & 인덱스 접근이므로 순서가 자연히 맞는다)의 수를 1 증가시키는 것으로 이 문제를 해결할 수 있다.
배운점
중간 과정에서 임시로 필요한 공간은 변수나 배열 형태로 저장할 수 있다는 거 기억하고 잘 써먹자.
dict를 defaultdict(value type) 으로 정의할 수 있으며, add를 통해 value 값을 추가할 수 있다는 거 기억하자.
최종적으로 구해야 하는 값에 초점을 맞춰서 불필요한 건 제거하고 최소한의 계산을 할 수 있도록 하자