코딩테스트 공부

[프로그래머스] 신고 결과 받기 (C++)

kkyoug 2025. 4. 12. 21:20

해당 문제는 해시를 활용하여 k번 이상 신고된 사람을 누가 신고했는지 체크하는 방법이다. 기본적으로 map, set에 관한 지식이 많고 범위기반 반복문을 잘 활용한다면 문제는 쉽게 해결되었다.


📌 문제 설명

시스템 동작 조건

  1. 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
  2. 신고 횟수에 제한은 없습니다.
  3. 동일한 유저를 여러 번 신고해도 1회로 처리됩니다.
  4. k번 이상 신고된 유저는 게시판 이용 정지됩니다.
  5. 유저가 신고한 내용은 취합 후 일괄 처리되며,
  6. 정지된 유저를 신고한 사람은 메일을 받게 됩니다.

🧾 예시

입력 예시:

id_list = ["muzi", "frodo", "apeach", "neo"];
report = ["muzi frodo", "apeach frodo", "frodo neo", "muzi neo", "apeach muzi"];
k = 2;

📊 신고 내역 분석

유저 ID 신고당한 횟수

muzi 1
frodo 2 ✅
apeach 0
neo 2 ✅

정지된 유저: frodo, neo


📩 메일 수신 결과

유저 ID 신고한 ID 정지된 ID 메일 수신 횟수

muzi ["frodo", "neo"] ["frodo", "neo"] 2
frodo ["neo"] ["neo"] 1
apeach ["muzi", "frodo"] ["frodo"] 1
neo 없음 없음 0

✅ 목표

각 유저가 정지된 유저를 신고했는지 확인해,
각 유저가 받은 메일 수를 반환하자!

🧑‍💻 C++ 코드

#include <string>
#include <vector>
#include <unordered_map>
#include <sstream>
#include <unordered_set>
#include <map>
using namespace std;

vector<int> solution(vector<string> id_list, vector<string> report, int k) {
    vector<int> answer;
    unordered_map<string, unordered_set<string>> check_report;
    unordered_map<string, int>result;
    
    // 신고 수 체크
    for(int i = 0; i<report.size(); i++){
        stringstream ss(report[i]); // muzi frodo
        string user_id, reported_id;
        ss>>user_id>>reported_id;
        
        // 중복 제거
        check_report[reported_id].insert(user_id); // frodo - {muzi, apeach}
    }
    
    for(auto & [reported_id, user_id] : check_report){ //frodo - {muzi, apeach}
        if(user_id.size() >=k){ // k명 이상에게 신고를 당했는지
            for(const auto & uid : user_id){ // 신고당한 횟수 기록
                result[uid]++;
            }
        }
    }
    
    for(string &id : id_list){
        answer.push_back(result[id]);
    }
    
    return answer;
}

 

✨ 코드 진행 과정 상세 설명

이 코드는 불량 이용자 신고 시스템을 구현한 것으로, 신고가 일정 횟수 이상 누적되면 해당 유저를 정지시키고, 정지된 유저를 신고한 사람들에게 처리 결과 메일을 보내는 로직을 담고 있습니다.

1. 변수 준비

unordered_map<string, unordered_set<string>> check_report;
unordered_map<string, int> result;
  • check_report는 누가 누구를 신고했는지 기록하는 자료구조입니다.
    → 중복 신고 방지를 위해 unordered_set 사용
    → 예: "frodo" → { "muzi", "apeach" }
  • result는 각 유저가 받은 결과 메일의 수를 저장합니다.

2. 신고 내역 정리 (중복 제거 포함)

for(int i = 0; i < report.size(); i++) {
    stringstream ss(report[i]);
    string user_id, reported_id;
    ss >> user_id >> reported_id;
    check_report[reported_id].insert(user_id);
}
  • report는 "신고자 신고당한사람" 형식의 문자열입니다.
  • stringstream으로 나눠서 신고자(user_id)와 피신고자(reported_id)를 분리합니다.
  • 동일한 사람이 동일 유저를 여러 번 신고해도 1번만 인정되도록 insert로 저장합니다.(set 사용)

3. 정지 대상 확인 + 메일 받을 사람 카운트

for(auto & [reported_id, user_id_set] : check_report) {
    if(user_id_set.size() >= k) {
        for(const auto & uid : user_id_set) {
            result[uid]++;
        }
    }
}
  • check_report를 순회하며, 신고자가 k명 이상이면 정지 대상입니다.
  • 해당 피신고자를 신고한 모든 사람(uid)은 메일을 받게 되므로 result[uid]++ 해줍니다.

4. 유저 순서에 맞게 정답 배열 생성

for(string &id : id_list){
    answer.push_back(result[id]);
}
  • 문제에서는 id_list에 있는 순서대로 결과 메일 수를 반환하라고 했기 때문에,
    → result에 없는 유저는 자동으로 0이 들어갑니다 (기본값).
  • 최종적으로 answer에 메일 받은 횟수를 담아 리턴합니다.

 

💡 핵심 개념 요약

  • unordered_map + unordered_set을 사용해 중복 제거 및 신고 내역 기록.
  • stringstream 으로 문자열에서 유저 ID 추출.
  • map 순회 (for (auto& [key, val] : map)) 를 통해 깔끔하게 처리.