파이썬 중복을 제거하는 set 잘 활용하기
1. 문제
https://programmers.co.kr/learn/courses/30/lessons/92334
신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다.
무지가 개발하려는 시스템은 다음과 같습니다.
각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다.
한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다.
k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.
이용자의 id가 담긴 문자열 배열 id_list, 각 이요자가 신고한 이용자의 id 정보가 담긴 문자열 배열 report,
정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return하도록 solution 함수를 완성해주세요.
2. 제한사항
3. 예시
4. 나의 풀이
잘 모르겠으면 예시 설명에 나온 흐름을 따라 그대로 구현하는게 바람직하다
제한사항중에 한 유저를 여러번 신고할 수 있지만 동일한 유저에 대한 신고 횟수는 1회로 처리한다
report의 형식을 보면 "이용자id 신고한id" 형태로 되어있고
예시 2번째를 보면 "ryan con", "ryan con", "ryan con", "ryan con" 모두 1회 신고한 것으로 취급한다고 했으니까
처음부터 report의 중복을 제거하는 방법으로 간다
리스트의 중복을 제거하는 방법은 set으로 변환하고 다시 list로 바꾸는 방법이 있다
def solution(id_list, report, k):
answer = []
report = list(set(report))
그 다음에 이제 누가 누구를 신고했는지, 누구는 몇번 신고당했는지를 구해야한다
신고당한 횟수를 비교해서 누가 정지당했는지 파악하고
정지당한 id를 누가 신고했는지 파악해야 누가 메일을 몇통 받았는지 구할 수 있으니까
def solution(id_list, report, k):
answer = []
report = list(set(report))
reporter_dict = {id_str:[] for id_str in id_list}
reported_dict = {id_str:0 for id_str in id_list}
리스트 뿐만 아니라 dict에서도 위와 같이 comprehension이 가능함
다음 report에서 하나씩 돌아서 누가 누구를 신고했는지 파악해서 reporter_dict와 reported_dict를 채운다
def solution(id_list, report, k):
answer = []
report = list(set(report))
reporter_dict = {id_str:[] for id_str in id_list}
reported_dict = {id_str:0 for id_str in id_list}
for rep in report:
rep_split = rep.split()
reporter,reported = rep_split[0],rep_split[1]
reporter_dict[reporter].append(reported)
reported_dict[reported] += 1
다음으로 reported_dict가 채워졌으니까 이제 누가 정지당했는지를 파악한다
reported_dict.items()를 이용해서 key,value를 순회할수 있다
def solution(id_list, report, k):
answer = []
report = list(set(report))
reporter_dict = {id_str:[] for id_str in id_list}
reported_dict = {id_str:0 for id_str in id_list}
for rep in report:
rep_split = rep.split()
reporter,reported = rep_split[0],rep_split[1]
reporter_dict[reporter].append(reported)
reported_dict[reported] += 1
stop_list = []
for reported,value in reported_dict.items():
if value >= k:
stop_list.append(reported)
신고당한 횟수가 k이상이면 정지당한 id 리스트에 집어넣어줌
다음으로 reporter_dict를 순회해서 정지메일을 발송함
def solution(id_list, report, k):
answer = []
report = list(set(report))
reporter_dict = {id_str:[] for id_str in id_list}
reported_dict = {id_str:0 for id_str in id_list}
for rep in report:
rep_split = rep.split()
reporter,reported = rep_split[0],rep_split[1]
reporter_dict[reporter].append(reported)
reported_dict[reported] += 1
stop_list = []
for reported,value in reported_dict.items():
if value >= k:
stop_list.append(reported)
for reporter,rep_list in reporter_dict.items():
stop = 0
for rep in rep_list:
if rep in stop_list:
stop += 1
answer.append(stop)
return answer
reporter_dict는 이용자id : [ 신고한 id 리스트 ]형태이고 stop은 정지메일 받은 횟수
rep_list인 신고한 id 리스트를 순회해서 각 id가 정지당한 id리스트인 stop_list에 존재하면
정지메일을 받았으니 stop에 1을 더해줘
처음에 dict comprehension할때 id_list에서 순서대로 reporter_dict에 집어넣었으니까
그냥 answer에 바로 stop을 append하면 된다
5. 다른 풀이
좋아요를 가장 많이 받은 풀이에 대해 보면 나랑 비슷함
def solution(id_list, report, k):
answer = [0] * len(id_list)
reports = {x : 0 for x in id_list}
for r in set(report):
reports[r.split()[1]] += 1
for r in set(report):
if reports[r.split()[1]] >= k:
answer[id_list.index(r.split()[0])] += 1
return answer
answer = [0] * len(id_list)를 해서 id_list 길이만큼 [0,0,0,0,...]으로 채워넣어
reports = {x : 0 for x in id_list}는 이용자id와 신고당한 횟수를 사전으로 만든거네
나랑 다른 점은 신고한 id리스트를 value로 가지는 사전 reporter_dict는 안만들었네
그래도 가능하다고??
다음 set(report)에서 report의 중복을 제거한 set에서 하나씩 순회한다음에
r.split()[1]은 신고당한 id를 나타내고 reports에 key로 넣고 1씩 더해주면 각 id가 몇번 신고당했는지 reports가 완성
다음 set(report)에서 또 하나씩 순회하는데
reports[r.split()[1]]은 신고당한 id가 몇번 신고당했는지 구해주고 이게 k 이상이면 이 id는 정지당한 id라는것
그렇다면 그 id를 신고한 이용자 id에 대해서 정지메일을 보낼건데 그 id를 신고한 이용자 id는 어떻게 찾냐??
r.split()[0]은 그 정지당한 id를 신고한 id이고 id_list.index()에 집어넣으면 그 정지당한 id를 신고한 id가
id_list에서 어디 index에 존재하는지 index를 반환하고
그러면 그 index는 정지메일을 한번 받은거니까 answer의 그 index 값을 1 더해주면 된다
이래서 처음에 answer = [0] * len(id_list)로 초기화했네
6. 되돌아보기
예시에서 설명해준 흐름에 따라 구현을 잘 했다
중복을 제거하는 set을 잘 활용했다
dict comprehension도 가능하다는 점 기억하면 좋다
'알고리즘 > 알고리즘 일반' 카테고리의 다른 글
파이썬 문자열 필수 스킬 - N-gram 순회하기, 대소문자를 무시한 변환 (0) | 2022.04.10 |
---|---|
그래프를 여러 집단으로 나누는 방법 (0) | 2022.04.09 |
2가지 모드로 나누어서 생각하기(코딩테스트 복기) (0) | 2022.04.01 |
최소비용으로 목표한 금액을 생산하는 방법은? (0) | 2022.03.14 |
2차원 배열 알고리즘 문제가 나오면 반드시 생각해야하는 스킬들 (0) | 2022.01.28 |