> [!date] published: 2022-04-30
[코딩테스트 연습 - 신고 결과 받기 \| 프로그래머스 스쿨](https://programmers.co.kr/learn/courses/30/lessons/92334)
## 🌟 문제
신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.
- 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
- 신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다.
- 한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다.
- k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
- 유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다.
이용자의 ID가 담긴 문자열 배열 `id_list`, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 `report`, 정지 기준이 되는 신고 횟수 `k`가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.
## 🌟 풀이
프로그래머스 형식의 문제를 너무 안푼 것 같아서 도전해봤는데... 문제 자체는 그렇게 어렵진 않았지만 입력 형식이 헷갈려서 죽는 줄 알았다ㅋㅋ 가끔은 프로그래머스 문제도 좀 풀어야겠다..
입력되는 정보는 유저의 ID (ID는 string 형식)가 담긴 `id_list`, `"신고한 사람 ID" "신고당한 사람 ID"` 형식의 문자열 배열 `report`, 그리고 정지 기준이 되는 신고 횟수 k이다. 그리고 return 해야 할 vector `answer`는 `id_list`의 순서대로 그 유저가 받는 처리 결과 메일의 개수를 저장해야 한다.
**(1)** 해야 할 일 첫번째는 당연히 `answer` 배열을 0으로 초기화 하는 것.
```cpp
vector<int> answer(id_list.size(), 0);
```
이렇게 초기화 해 주면 된다.
**(2)** 다음에는 `"신고한 사람 ID" "신고당한 사람 ID"` 형식으로 입력되는 정보를 파싱하기 위해서 get_name 함수를 만들어줬다. 형식이 딱 정해져 있기 때문에 가운데 공백을 기준으로 앞쪽과 뒷쪽으로 나누어서 pair 형태로 반환해주었다.
**(3)** 그리고 유저의 ID를 key로, 해당 유저가 신고한 ID의 목록의 set을 value로 갖는 map `singo_list`, 유저 ID를 key로, 해당 유저가 신고당한 횟수를 value로 하는 map `singodang_cnt`를 선언해주었다. 네이밍 센스가 참 어디 선보이기 너무 민망한 수준이다...
`singo_list`의 value가 되는 신고한 ID의 목록을 set으로 설정한 이유는 중복 신고를 허용하지 않기 때문이다! 사실 신고 목록을 저장하는 반복문에서 중복 신고의 경우에는 `singodang_cnt`의 내용을 변경하면 안되기 때문에 중복 신고의 경우를 걸러주는 부분이 있어서 내가 짠 코드 내에서는 set으로 굳이 안해도 되었을 것 같긴 하다. ㅎㅎ
**(4)** 다음에는 신고 목록을 저장해준다! 앞서 말했듯이 `report` 배열을 돌면서 `singo_list["신고자 ID"]` 에 `"신고당한 ID"`가 있는지 확인한 후에, 없다면 `singo_list["신고자 ID"]`에 추가하고 `singodang_cnt["신고당한 ID"]`를 증가시켜준다.
**(5)** 마지막으로는 id_list 내의 ID에 해당하는 singo_list를 또 돌면서 `singodang_cnt`의 값이 k보다 크거나 같은 경우가 있는지 확인하고, 있다면 그 신고자 ID에 해당하는 인덱스 (코드를 보면 알겠지만, `id_list`를 순차적으로 탐색하고 있기 때문에 굳이 ID ↔️ index로 변환하는 작업 없이 작업하고있는 인덱스 i를 그대로 써줘도 괜찮았다.)의 `answer` 값을 증가시켜줬다.
끝!
## 🌟 코드
```cpp
#include <string>
#include <vector>
#include <set>
#include <map>
#include <utility>
using namespace std;
pair<string, string> get_name(string report)
{
pair<string, string> ret;
int idx = 0;
while (report[idx] != ' ')
idx++;
ret.first = report.substr(0, idx);
idx++;
ret.second = report.substr(idx, report.length() - idx);
return (ret);
}
vector<int> solution(vector<string> id_list, vector<string> report, int k) {
vector<int> answer(id_list.size(), 0);
map<string, set<string> > singo_list; // (유저 ID, 해당 유저가 신고한 ID의 목록)
map<string, int> singodang_cnt; // (유저 ID, 해당 유저가 신고당한 횟수)
pair<string, string> name; // first: 이용자 ID, second: 신고한 ID
// 신고당한 횟수 초기화
for(int i = 0; i < id_list.size(); i++)
singodang_cnt[id_list[i]] = 0;
// 신고 목록 저장
for(int i = 0; i < report.size(); i++)
{
name = get_name(report[i]);
// 앞선 신고 이력이 없을 경우 추가하고 신고 횟수를 늘린다.
if (singo_list[name.first].find(name.second) == singo_list[name.first].end())
{
singo_list[name.first].insert(name.second);
singodang_cnt[name.second]++;
}
}
// id list를 돌면서 자신이 신고한 ID 중 신고 횟수가 k가 넘는 경우에 answer의 값을 증가시킨다.
for(int i = 0; i < id_list.size(); i++)
{
for(auto iter = singo_list[id_list[i]].begin(); iter != singo_list[id_list[i]].end(); iter++)
{
if (singodang_cnt[*iter] >= k)
answer[i]++;
}
}
return answer;
}
```