92334. 신고 결과 받기

2022-04-30
프로그래머스 92334번 풀이

이 글은 Obsidian에서 마이그레이션되었으며, 그 과정에서 AI의 도움을 받았습니다. 오류나 누락된 내용이 있다면 댓글로 알려주세요!

문제

코딩테스트 연습 - 신고 결과 받기 | 프로그래머스 스쿨

풀이

아이디어

프로그래머스 형식의 문제를 너무 안푼 것 같아서 도전해봤는데… 문제 자체는 그렇게 어렵진 않았지만 입력 형식이 헷갈려서 죽는 줄 알았다ㅋㅋ 가끔은 프로그래머스 문제도 좀 풀어야겠다..

입력되는 정보는 유저의 ID (ID는 string 형식)가 담긴 id_list, "신고한 사람 ID" "신고당한 사람 ID" 형식의 문자열 배열 report, 그리고 정지 기준이 되는 신고 횟수 k이다. 그리고 return 해야 할 vector answerid_list의 순서대로 그 유저가 받는 처리 결과 메일의 개수를 저장해야 한다.

(1) 해야 할 일 첫번째는 당연히 answer 배열을 0으로 초기화 하는 것.

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 값을 증가시켜줬다.

끝!

코드

#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;
}