[Programmers] Lv.1 신고 결과 받기 _JavaScript
프로그래머스 Lv1. 신고 결과 받기 문제 풀이
🧶 문제 설명
신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.
- 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
- k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다.
다음은 전체 유저 목록이 ["muzi", "frodo", "apeach", "neo"]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다.
유저 ID | 유저가 신고한 ID | 설명 |
"muzi" | "frodo" | "muzi"가 "frodo"를 신고했습니다. |
"apeach" | "frodo" | "apeach"가 "frodo"를 신고했습니다. |
"frodo" | "neo" | "frodo"가 "neo"를 신고했습니다. |
"muzi" | "neo" | "muzi"가 "neo"를 신고했습니다. |
"apeach" | "muzi" | "apeach"가 "muzi"를 신고했습니다. |
각 유저별로 신고당한 횟수는 다음과 같습니다.
유저 ID | 신고당한 횟수 |
"muzi" | 1 |
"frodo" | 2 |
"apeach" | 0 |
"neo" | 2 |
위 예시에서는 2번 이상 신고당한 "frodo"와 "neo"의 게시판 이용이 정지됩니다. 이때, 각 유저별로 신고한 아이디와 정지된 아이디를 정리하면 다음과 같습니다.
유저 ID | 유저가 신고한 ID | 정지된 ID |
"muzi" | ["frodo", "neo"] | ["frodo", "neo"] |
"frodo" | ["neo"] | ["neo"] |
"apeach" | ["muzi", "frodo"] | ["frodo"] |
"neo" | 없음 | 없음 |
따라서 "muzi"는 처리 결과 메일을 2회, "frodo"와 "apeach"는 각각 처리 결과 메일을 1회 받게 됩니다.
이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, 각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요.
제한사항
- 2 ≤ id_list의 길이 ≤ 1,000
- 1 ≤ report의 길이 ≤ 200,000
- 1 ≤ k ≤ 200, k는 자연수입니다.
- return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.
입출력 예
id_list | report | k | result |
["muzi", "frodo", "apeach", "neo"] | ["muzi frodo","apeach frodo","frodo neo","muzi neo","apeach muzi"] | 2 | [2,1,1,0] |
["con", "ryan"] | ["ryan con", "ryan con", "ryan con", "ryan con"] | 3 | [0,0] |
🧶 풀이법
1. key: id, value: {Set(신고한 id들)} 형식의 obj 객체 생성
2. 유저 한명씩 순회하면서 누가 몇 번 신고당한지 name 배열에 기록 (name의 인덱스가 곧 유저의 인덱스이므로 숫자만 기록)
3. 유저 한명씩 다시 순회하면서 k이상의 횟수로 신고된 id를 가지고 있을 경우 answer 배열에 +1
🧶 코드
function solution(id_list, report, k) {
let answer = new Array(id_list.length).fill(0);
let name = new Array(id_list.length).fill(0);
let obj = {};
// 1. key: id, value: {Set(신고한 id들)} 형식의 obj 객체 생성
// 유저당 set 생성
id_list.forEach((e) => {
obj[e] = new Set();
})
report.map((info) => {
info = info.split(" ");
obj[info[0]].add(info[1]);
})
// 유저 : set(내가 신고한 유저들)
// {
// muzi: Set(2) { 'frodo', 'neo' },
// frodo: Set(1) { 'neo' },
// apeach: Set(2) { 'frodo', 'muzi' },
// neo: Set(0) {}
// }
// 2. 유저 한명씩 순회하면서 누가 몇 번 신고당한지 name 배열에 기록 (name의 인덱스가 곧 유저의 인덱스이므로 숫자만 기록)
id_list.map(e => {
for (i in id_list) {
obj[e].has(id_list[i]) && name[i]++;
}
})
// name : 신고당한 횟수
// 3. 유저 한명씩 다시 순회하면서 k이상의 횟수로 신고된 id를 가지고 있을 경우 answer 배열에 +1
for(idx in id_list) {
if(name[idx] >= k) { // idx : 2번 이상 신고당한 유저의 인덱스
for (j in id_list) { // 그 유저를 신고한 유저 찾기
obj[id_list[j]].has(id_list[idx]) && answer[j]++;
}
}
}
return answer;
}
🧶 다른 풀이법
function solution(id_list, report, k) {
let reports = [...new Set(report)].map(a=>{return a.split(' ')});
// reports :
// [
// [ 'muzi', 'frodo' ],
// [ 'apeach', 'frodo' ],
// [ 'frodo', 'neo' ],
// [ 'muzi', 'neo' ],
// [ 'apeach', 'muzi' ]
// ]
let counts = new Map();
for (const bad of reports){
counts.set(bad[1],counts.get(bad[1])+1||1)
}
// count : 신고당한 유저 => 신고당한 횟수
// Map(3) { 'frodo' => 2, 'neo' => 2, 'muzi' => 1 }
let good = new Map();
for(const report of reports){
if(counts.get(report[1])>=k){
good.set(report[0],good.get(report[0])+1||1)
}
}
// good : 신고한 유저 => 메일받은 횟수
// Map(3) { 'muzi' => 2, 'apeach' => 1, 'frodo' => 1 }
let answer = id_list.map(a=>good.get(a)||0)
return answer;
}
전개 연산자(...)와 Map, || 를 사용하면 위처럼 더 깔끔한 코드를 짤 수도 있더라구요!
🧶 후기
저는 아직 갈 길이 먼 것 같아요😩