[프로그래머스/92334] 신고 결과 받기

☑️ 문제

프로그래머스 92334

☑️ 풀이

첫 번째 풀이

import java.util.*;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
		    // 1.
        Set<String> set = new HashSet<>();
        for (String s : report) {
            set.add(s);
        }
        
        Map<String, Integer> countMap = new HashMap<>();
        Map<String, ArrayList<String>> reportMap = new HashMap<>();
        
        // 2. 
        Iterator iter = set.iterator();
        while (iter.hasNext()) {
            String[] str = iter.next().toString().split(" ");
            countMap.put(str[1], countMap.getOrDefault(str[1], 0) + 1);
            if (!reportMap.containsKey(str[0])) {
                reportMap.put(str[0], new ArrayList<>());
            }
            reportMap.get(str[0]).add(str[1]);
        }
        
        // 3. 
        List<String> admittedUser = new ArrayList<>();
        for (String s : id_list) {
            if (countMap.getOrDefault(s, 0) >= k) {
                admittedUser.add(s);
            }
        }
        
        // 4. 
        int[] answer = new int[id_list.length];
        for (int i = 0; i < id_list.length; i++) {
            String id = id_list[i];
            if (reportMap.containsKey(id)) {
                List<String> nameList = reportMap.get(id);
                for (int j = 0; j < admittedUser.size(); j++) {
                    String name = admittedUser.get(j);
                    if (nameList.contains(name)) {
                        answer[i] += 1; 
                    }
                }
            }
        }
                
        return answer;
    }
}
  • 한 개의 HashSet과 두 개의 HashMap을 사용했다.
    • Set<String> set : report 중복 체크용
    • Map<String, Integer> countMap : key - 신고를 받은 이용자, value - 신고받은 횟수
    • Map<String, ArrayList<String>> reportMap : key - 이용자, value - 신고한 이용자의 id 모음 ArrayList
      1. HashSet을 사용하여 report의 중복을 체크한다. (중복 신고는 인정되지 않기 때문)
      2. HashSet을 순회하면서 countMapreportMap을 구성한다.
      3. countMap을 순회하면서 신고로 인정될 id를 따로 admittedUser에 담는다.
      4. 각 이용자별 메일을 받는 횟수를 체크한다. 1. 먼저 id_list를 순회하면서 reportMap에 id가 있다면 신고한 이용자의 리스트를 가져온다. 2. 신고한 리스트에 admittedUser에 들어있는 id와 일치하는 id가 있다면 answer 배열의 값을 1씩 증가시킨다.
      5. answer 배열을 리턴한다.
  • 시간 복잡도
    • HashSet으로 중복 제거 → O(N) (N: report 길이)
    • HashMap 구성 → O(N)
    • 정지될 id 체크 → O(M) (M: id_list 길이)
    • 메일 받는 횟수 체크 → O(M * A * L) (A: AdmittedUser 길이, L: nameList 길이)
    • 최종 시간 복잡도 → O(M * A * L)

두 번째 풀이

import java.util.*;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
        Set<String> set = new HashSet<>();
        for (String s : report) {
            set.add(s);
        }
        
        Map<String, Integer> countMap = new HashMap<>();
        Map<String, HashSet<String>> reportMap = new HashMap<>();
        Iterator iter = set.iterator();
        while (iter.hasNext()) {
            String[] str = iter.next().toString().split(" ");
            countMap.put(str[1], countMap.getOrDefault(str[1], 0) + 1);
            if (!reportMap.containsKey(str[0])) {
                reportMap.put(str[0], new HashSet<String>());
            }
            reportMap.get(str[0]).add(str[1]);
        }
        
        List<String> admittedUser = new ArrayList<>();
        for (String s : id_list) {
            if (countMap.getOrDefault(s, 0) >= k) {
                admittedUser.add(s);
            }
        }
        
        int[] answer = new int[id_list.length];
        for (int i = 0; i < id_list.length; i++) {
            String id = id_list[i];
            if (reportMap.containsKey(id)) {
                HashSet<String> nameSet = reportMap.get(id);
                for (int j = 0; j < admittedUser.size(); j++) {
                    String name = admittedUser.get(j);
                    if (nameSet.contains(name)) {
                        answer[i] += 1; 
                    }
                }
            }
        }
                
        return answer;
    }
}
  • 첫 번째 풀이에서는 reportMapValueArrayList를 사용했고, ArrayList.contains() 를 사용해 선형 탐색을 했기때문에 시간 복잡도가 컸다.
  • ArrayList를 대신해서 HashSet을 사용하면 HashSet.contains() 사용 시 시간복잡도가 O(1)이 되어 최종 시간복잡도가 O(N^2)으로 줄어든다.

세 번째 풀이

import java.util.*;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
        
        Map<String, HashSet<String>> reportMap = new HashMap<>();
        Map<String, Integer> countMap = new HashMap<>();
        
        for (String r : report) {
            String[] reportStr = r.split(" ");
            if (!reportMap.containsKey(reportStr[1])) {
                reportMap.put(reportStr[1], new HashSet<>());
            }
            reportMap.get(reportStr[1]).add(reportStr[0]);
        }
        
        for (int i = 0; i < id_list.length; i++) {
            if (reportMap.containsKey(id_list[i])) {
                HashSet<String> userSet = reportMap.get(id_list[i]);
                if (userSet.size() >= k) {
                    Iterator iter = userSet.iterator();
                    while (iter.hasNext()) {
                        String name = iter.next().toString();
                        countMap.put(name, countMap.getOrDefault(name, 0) + 1);
                    }
                }
            }
        }
        
        int[] answer = new int[id_list.length];
        for (int i = 0; i < id_list.length; i++) {
            answer[i] = countMap.getOrDefault(id_list[i], 0);
        }
                
        return answer;
    }
}
  • 책의 풀이를 참고했다.
  • 앞의 풀이와 다른 점은
    • Map<String, HashSet<String>> reportMap : key - 신고를 당한 이용자, value - 신고한 이용자의 HashSet
    • Map<String, Integer> countMap : key - 이용자, value - 메일을 받는 횟수
    • reportMap의 value로 HashSet을 사용했기 때문에 따로 report 중복 체크를 해줄 필요가 없어졌다.
  • reportMapHashSet의 크기가 k보다 크거나 같다면 해당 이용자는 신고 횟수를 충족한다는 점을 이용해 해당 HashSet을 순회하면서 countMap을 완성하였다.
  • 시간복잡도
    • report를 순회하면서 reportMap 완성 → O(N) (N: report 길이)
    • id_list을 순회하면서 reportMap의 HashSet 찾음, HashSet 순회하면서 countMap 완성 → O(M^2) (M: id_list 길이)
    • id_list 순회하면서 answer 배열 완성 → O(M)
    • 최종 시간복잡도 → O(N + M^2)

© 2021. All rights reserved.

yaejinkong의 블로그