1. 문제 설명
신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다.
- 각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다.
- 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. 제한사항
2 ≤ id_list의 길이 ≤ 1,000
1 ≤ report의 길이 ≤ 200,000
1 ≤ k ≤ 200, k는 자연수입니다.
return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다.
3. 입출력 예
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] |
4. 입출력 예 설명
- 입출력 예 #1
문제의 예시와 같습니다.
- 입출력 예 #2
"ryan"이 "con"을 4번 신고했으나, 주어진 조건에 따라 한 유저가 같은 유저를 여러 번 신고한 경우는 신고 횟수 1회로 처리합니다. 따라서 "con"은 1회 신고당했습니다. 3번 이상 신고당한 이용자는 없으며, "con"과 "ryan"은 결과 메일을 받지 않습니다. 따라서 [0, 0]을 return 합니다.
5. 풀이
import java.util.*;
class Solution {
public int[] solution(String[] id_list, String[] report, int k) {
int [] answer = new int [id_list.length]; //answer 크기 지정;
HashSet<String> re = new HashSet<String>(); //report 중복값 제거 작업;
for(int i =0; i<report.length;i++) {
re.add(report[i]);
}
Iterator<String> rei = re.iterator();
String[] Re=new String[re.size()];
while (rei.hasNext()) { //report 중복 제거
for(int i=0; i<re.size(); i++) {
Re[i] = rei.next();
}
}
String [][] list = new String [id_list.length][Re.length]; //id_list에서 각 인원이 Re만큼 신고한 내역 저장
for(int i=0; i<id_list.length; i++) {//id_list 만큼 반복
for(int t =0; t<Re.length; t++) { // report만큼 반복
if(Re[t]!=null&&id_list[i].equals(Re[t].substring(0, id_list[i].length()))) {//id_list[i]와 report[i](앞자리만) 같다면
list[i][t]=Re[t].substring(id_list[i].length()+1);
}
}
}
int cnt =1;
int [][]b = new int [id_list.length] [Re.length];
for(int i =0; i<id_list.length; i++) {//a의 배열 중 대상 선택
for(int t =0; t<Re.length; t++) {
for(int c=0; c<id_list.length; c++) {//a배열 중 비교할 요소 선택
for(int g =0; g<Re.length; g++) {
if(list[i][t]!=null&&list[i][t].equals(list[c][g])) {
b[i][t]+=cnt;
}
}
}
}
}
for(int i =0; i<id_list.length; i++) {
for(int t =0; t<Re.length; t++) {
if(b[i][t]>=k) {
answer[i]++;
}
}
}
return answer;
}
}
5.1 재풀이
1. report 내 중복 제거
2. id_list 내 이름과 report 내 신고자 이름이 같다면, 신고당한 이름을 list배열에 저장
3. list 배열 내 요소가 중복되고 그 수가 k 이상일 때의 경우 그 수를 합산하여 answer에 저장
4. 결과 : 런타임 오류
6. 최종 풀이
나름 해결한다고 했는데, 너무 1차원 적이고 생각나는 대로~ 손가는 대로~ 저질러버렸으니 당연한 결과이기도 하다,,
실행 시간을 줄이고자 list 크기를 줄이거나 list 배열을 생성 시 바로 3번의 방식을 진행해보려고 하였으나, 다른 함수를 사용해야겠다는 생각이 들었다.
HashMap의 사용과 보다 간단한 알고리즘을 이해하기 쉽게 정리하신 분의 정보를 참고하였다..
편의상 report 내 "muzi frodo" 중 muzi(신고자) frodo(범죄자)라고 하였다..
import java.util.*;
class Solution {
public int[] solution(String[] id_list, String[] report, int k) {
int[] answer = new int[id_list.length];
Map<String, HashSet<String>> map = new HashMap<>(); //1
Map<String, Integer> idxMap = new HashMap<>();
for (int i = 0; i < id_list.length; i++) { //2
String name = id_list[i];
map.put(name, new HashSet<>());
idxMap.put(name, i);
}
for (String s : report) { //3
String[] str = s.split(" ");
String user = str[0];
String singo = str[1];
map.get(singo).add(user);
}
for (int i = 0; i < id_list.length; i++) { //4
HashSet<String> send = map.get(id_list[i]);
if (send.size() >= k) {
for (String name : send) {
answer[idxMap.get(name)]++;
}
}
}
return answer;
}
}
//1
Map<String, HashSet<String>> map = new HashMap<>();
Map<(key 값 : user ID, 범죄자), (value 값 : key를 신고한 사람 user ID)> map
Map<String, Integer> idxMap = new HashMap<>();
Map<key 값 : user ID), (value 값 : id_list에 접근하기 위한 임의 인덱스 값 : 범죄자)> idxMap
//2
id_list의 요소를 name에 저장
map.put(name, new HashSet<>()); → map에 key 값 : name, value 값 : 선언 시 설정한 값 저장
(map 출력 시 ⇢ {muzi=[], neo=[], frodo=[], apeach=[]})
idxMap.put(name, i); → idxMap에 key 값 : name, value 값 : 인덱스 값 저장
(idxMap 출력 시 ⇢ {muzi=0, neo=3, frodo=1, apeach=2})
//3
report 내 요소를 s에 담는다.
String[] str = s.split(" "); → " "를 기준으로 각각 str [0](신고당한 사람), str[i](이용자를 신고한 사람)에 저장한다.
String user = str[0]; → singo에게 신고당한 사람 : 범죄자
String singo = str[1]; → user를 신고한 사람 : 신고자
map.get(singo).add(user); → map 내 singo와 같은 요소에 신고당한 사람을 저장해라
(map 출력 시 ⇢{muzi=[apeach], neo=[muzi, frodo], frodo=[muzi, apeach], apeach=[]})
//4
send에 신고자를 저장
신고자가 저장된 send의 크기(send.size())가 k 이상이라면
idxMap의 인덱스 값을 name으로 불러온 뒤
send.size만큼 1씩 더하여 최종 메일 받을 수를 저장하면 된다.
다시 정리를 하면서 단순한 알고리즘뿐만 아니라 Map, hashmap 등 생소한 함수도 공부하게 되었다..
더 많이 알고 아는 것을 더 많이 자유롭게 사용할 수 있도록 하여야겠다...
[출처]
https://yeoeun-ji.tistory.com/m/113
https://codechacha.com/ko/java-map-hashmap/#1-hashmapput
https://reakwon.tistory.com/151
'코딩테스트(Level 0~1)' 카테고리의 다른 글
[JAVA, Programmers] 옹알이(1)(자바) (0) | 2022.11.24 |
---|---|
[JAVA, Programmers] 같은 숫자는 싫어(자바) (0) | 2022.11.23 |
[JAVA, Programmers] 최대공약수와 최소공배수(자바) (0) | 2022.11.22 |
[JAVA, Programmers] 행렬의 덧셈(자바) (0) | 2022.11.22 |
[JAVA, Programmers] 부족한 금액 계산하기(자바) (1) | 2022.11.21 |