프로그래머스 신고 결과 받기 | 구현 문제에서 문제 해석이 먼저인 이유

이 문제는 코드보다 먼저 문제를 단계로 끊어서 보는 게 핵심이다.

처음 보면 그렇게 어려워 보이지 않는다.

누가 누구를 신고했고, 일정 횟수 이상 신고당하면 정지되고, 그 사람을 신고한 사람에게 메일이 간다.

말로 하면 단순한데, 막상 구현 들어가면 자꾸 꼬인다.

이유는 하나다.

이 문제는 한 번에 처리하려고 하면 안 되고,

반드시 아래 순서로 나눠서 봐야 한다.

  • 중복 신고 제거
  • 신고 관계 저장
  • 신고당한 횟수 카운트
  • 정지 대상 판별
  • 메일 수 계산

즉, 이 문제는 딕셔너리 문법 문제가 아니라

구현 문제를 구조화하는 문제에 더 가깝다.


🔗 문제 링크

프로그래머스 92334 - 신고 결과 받기

https://school.programmers.co.kr/learn/courses/30/lessons/92334


문제 정리

입력은 이렇게 들어온다.

  • id_list : 전체 유저 목록
  • report : "신고자 피신고자" 형태의 문자열 목록
  • k : 정지 기준 신고 횟수

출력은

각 유저가 최종적으로 받게 되는 메일 개수다.

문제에서 중요한 조건은 이거다.

  1. 같은 사람이 같은 사람을 여러 번 신고해도 1번만 인정
  2. 어떤 유저가 k번 이상 신고당하면 정지
  3. 정지된 유저를 신고한 사람에게만 메일 발송

즉, 이 문제는 단순히 “누가 많이 신고당했나”만 보는 문제가 아니다.

신고 관계카운트를 같이 봐야 한다.


✅ 핵심 아이디어

이 문제는 아래 4단계로 나누면 된다.

  1. report를 set으로 바꿔서 중복 신고 제거
  2. 신고 관계 저장
  3. 피신고 횟수 카운트
  4. 각 유저가 신고한 대상 중 정지된 사람이 몇 명인지 계산

이 흐름만 잡히면 구현은 생각보다 길지 않다.


정답

def solution(id_list, report, k):
    report = set(report)

    reported_by = {user: [] for user in id_list}
    reported_count = {user: 0 for user in id_list}

    for r in report:
        reporter, target = r.split()
        reported_by[reporter].append(target)
        reported_count[target] += 1

    answer = []

    for user in id_list:
        mail_count = 0
        for target in reported_by[user]:
            if reported_count[target] >= k:
                mail_count += 1
        answer.append(mail_count)

    return answer

생각해야 하는 부분

이 문제는 구현 디테일보다

각 자료구조에 뭘 담을지를 먼저 정해야 한다.


1. 먼저 중복 신고를 제거해야 한다

이 문제에서 제일 먼저 해야 할 일은 이거다.

report = set(report)

문제 조건상

같은 사람이 같은 사람을 여러 번 신고해도 1번만 인정된다.

즉, 나중에 카운팅하기 전에

이 중복부터 제거해야 한다.

이걸 뒤로 미루면

신고 횟수 자체가 잘못 올라가서 전체 결과가 틀어진다.


2. 신고 관계 저장과 피신고 횟수 카운트는 분리해서 봐야 한다

이 문제는 딕셔너리가 두 종류 필요하다.

reported_by = {user: [] for user in id_list}
reported_count = {user: 0 for user in id_list}

각 역할은 이렇다.

  • reported_by[user]
    • 이 유저가 누구를 신고했는지 저장
  • reported_count[user]
    • 이 유저가 몇 번 신고당했는지 저장

즉, 하나는 관계 저장, 하나는 횟수 카운트다.

이걸 한 구조에 다 몰아넣으려고 하면 바로 헷갈린다.


3. split()으로 신고자와 피신고자를 나눈다

report 안에는 이런 문자열이 들어 있다.

"muzi frodo"

이걸 쪼개면

  • 신고자 = muzi
  • 피신고자 = frodo

가 된다.

reporter, target = r.split()

이 문제에서 split()은 그냥 문자열 처리 문법이 아니라,신고 관계를 분해하는 핵심 단계다.


4. 마지막엔 “내가 신고한 사람 중 정지된 사람 수”를 세면 된다

앞 단계까지 끝나면

각 유저가 신고한 목록과, 각 유저가 몇 번 신고당했는지가 정리돼 있다.

그다음은 단순하다.

for user in id_list:
    mail_count = 0
    for target in reported_by[user]:
        if reported_count[target] >= k:
            mail_count += 1
    answer.append(mail_count)

즉,

내가 신고한 사람들 중에서

최종적으로 정지된 사람이 몇 명인지 세면 그게 메일 개수다.


예외처리 / 주의할 점

⚠️ 1. 중복 신고 제거를 빼먹으면 바로 틀린다

이 문제에서 제일 먼저 챙겨야 하는 조건이 이거다.

같은 사람이 같은 사람을 여러 번 신고해도 1번만 인정된다.

그래서 무조건 먼저

report = set(report)

이걸 해줘야 한다.

이걸 안 하면 reported_count가 실제보다 크게 잡힌다.


⚠️ 2. 메일은 “정지된 사람을 신고한 사람”에게만 간다

처음 보면

“신고당한 횟수 세고, 많이 당한 사람 찾고, 끝”처럼 보일 수 있다.

근데 문제는 거기서 안 끝난다.

출력은 정지된 사람 목록이 아니라

각 유저가 몇 개의 메일을 받는지다.

즉 마지막 단계까지 꼭 가야 한다.


⚠️ 3. id_list 순서대로 답을 만들어야 한다

출력은 딕셔너리 순서가 아니라

문제에서 준 id_list 순서 기준이다.

그래서 마지막도 이렇게 가야 한다.

for user in id_list:
    ...
    answer.append(mail_count)

이 순서를 놓치면

값은 맞아도 제출 형식이 틀릴 수 있다.


⚠️ 4. 이 문제는 자료구조 역할 분리가 중요하다

이 문제는 딕셔너리 하나로 다 밀어붙이려고 하면 어렵다.

  • 신고 관계
  • 피신고 횟수
  • 메일 계산

이 역할을 나눠서 봐야 한다.

즉, 코드를 줄이는 것보다

구조를 분리해서 보는 게 먼저다.


내 시행착오

이 문제는 내가 처음에 꽤 오래 붙잡았던 문제다.

이유는 코드 문법보다 문제 구조가 한 번에 안 보였기 때문이다.


1. 한 번에 처리하려고 했다

처음엔 대충 이런 식으로 생각했다.

  • report 나누고
  • 누가 누구 신고했는지 넣고
  • 정지자 찾고
  • 메일 보내고

말로 하면 쉬운데,

이걸 한 흐름으로 바로 코드로 옮기려니까 자료형이 계속 꼬였다.

결국 이 문제는

한 번에 처리하려고 하면 안 되고,

반드시 중간 구조를 먼저 만든다고 생각해야 했다.


2. 자료구조 역할을 명확히 못 나눴다

처음에는 딕셔너리 하나에 다 넣으려고 했는데,

그러면

  • 누가 누구를 신고했는지
  • 몇 번 신고당했는지

이 둘이 섞여서 헷갈렸다.

이 문제는 결국 딕셔너리를 2개로 나누고 나서야 정리됐다.

  • 신고 관계용
  • 카운트용

이렇게.


3. 출력이 “정지자”가 아니라 “메일 수”라는 걸 중간에 놓쳤다

이 문제는 정지 대상 찾는 걸로 끝나는 문제가 아니다.

마지막 출력은

각 유저가 받는 메일 수다.

즉, 정지 대상 판별은 중간 단계일 뿐이고

진짜 마지막은 메일 개수 계산이다.

이걸 중간에 놓치면 문제를 다 푼 것 같아도 끝까지 못 간다.


한 줄 정리

이 문제는 딕셔너리 문법 문제라기보다,

신고 관계 / 카운트 / 결과 계산을 단계별로 구조화해서 보는 구현 문제다.