본 포스팅은 wakekang님의 티스토리 게시글을 참고하였습니다.
본 문제에선 세 가지 중요한 개념을 사용하였다. 바로 unordered_map
, set
, 그리고 stringstream
이다. 각각 <unordered_map>
, <set>
, <sstream>
헤더를 포함하여 사용할 수 있다.
위 개념들을 사용한 이유는 다음과 같다.
idx_map
과 report_map
이라는 두 개의 맵을 사용한다. idx_map
은 기본적으로 주어지는 유저 목록인 id_list
를 빠르게 접근하기 위함, report_map
은 신고자 목록을 저장하기 위함이다.report_map
의 value 자료형을 vector와 같은 배열 컨테이너로 사용할 수도 있겠지만, 동일한 유저에 대한 신고 횟수는 1회로 처리 즉, 중복을 허용하지 않는다는 특성을 고려하여 set 자료구조를 사용한다.report
객체가 "muzi frodo"처럼 신고자와 피신고자를 한 문자열에 묶여 있기 때문에 이를 간편하게 파싱하는 용도로 사용하는 클래스이다.바로 코드를 살펴보자.
#include <string>
#include <vector>
#include <unordered_map>
#include <set>
#include <sstream>
using namespace std;
vector<int> solution(vector<string> id_list, vector<string> report, int k) {
vector<int> answer(id_list.size(), 0); // 반드시 초기화를 해준다.
unordered_map<string, int> idx_map; // id_list라는 벡터 전체를 탐색하지 않고 빠르게 탐색
for(int index = 0; index < id_list.size(); index++){
idx_map[id_list[index]] = index; // 유저의 아이디를 key로 넣고
} // id_list에서의 인덱스를 value로 저장한다.
unordered_map<string, set<string>> report_map; // 실제 신고 내용을 저장하는 맵
stringstream reporting_stream; // 신고 내용이 담긴 string을 파싱하기 위한 stringstream
for(auto reporting_str : report){
reporting_stream.str(reporting_str); // stream의 값을 원하는 string으로 바꾼다.
string reporter, reported;
reporting_stream >> reporter >> reported; // 공백에 따라 문자열 파싱이 가능하다.
report_map[reported].insert(reporter);
reporting_stream.clear(); // clear를 해줘야 새로운 문자열 str을 받았을 때
} // 문자열의 첫 위치부터 읽어낼 수 있다.
for(auto it : report_map){
if(it.second.size() >= k){ // 특정 유저에 대한 신고자가 k명 이상일 때
for(auto reporter_list : it.second){ // it.second : 신고자 목록(set<string>)
int idx = idx_map[reporter_list]; // 피신고자의 인덱스를 idx_map에서 찾음
answer[idx]++;
}
}
}
return answer;
}