Algorithms/- 프로그래머스

프로그래머스 - 신고 결과 받기 [자바]

자굿 2022. 2. 2. 23:54
 

코딩테스트 연습 - 신고 결과 받기

문제 설명 신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다. 각 유저는 한 번에 한 명의

programmers.co.kr

 

정답

 

시간 초과 정답

import java.util.*;
import java.util.stream.*;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
        //유저당 신고한 사람 set 한 list로 가지고 있어야 함.
        //신고된 사람
        //유저가 신고한 사람 setlist와 신고된 사람 카운트 해서 각 index에 맞게 ++

        Set<String> sset = new HashSet<>();
        for(String str: report){
            sset.add(str);
        }
        //set된 신고
        report = sset.stream().toArray(String[]::new);

        //[유저,[신고한 유저들]]
        Map<String, List<String>> ssmap = new HashMap<>();
        for(String str1 :id_list){
            List<String> slist = new ArrayList<>();
            for(String str2 : report){
                String[] ar = str2.split(" ");
                if(str1.equals(ar[0])){
                    slist.add(ar[1]);
                }
            }
            ssmap.put(str1, slist);
        }

        //유저별 신고 카운트
        Map<String, Integer> simap = new HashMap<>();
        for(String str1 : report){
            String[] ar1 = str1.split(" ");
            simap.put(ar1[1], simap.getOrDefault(ar1[1], 0) + 1);
        }

        //신고된 유저들
        List<String> slist = new ArrayList<>();
        for(String str1 : simap.keySet()){
            if(simap.get(str1) >= k){
                slist.add(str1);
            }
        }

        //유저가 신고한 리스트와 신고된 유저들 카운트
        int[] answer = new int[id_list.length];
        int idx = 0;
        for(String str1 : ssmap.keySet()){
            for(int i=0; i<id_list.length; i++){
                if(str1.equals(id_list[i])){
                    idx = i;
                }
            }

            List<String> slist1 = ssmap.get(str1);//유저가 신고한 리스트들
            for(String str2 : slist1){
                if(slist.contains(str2)){
                    answer[idx]++;
                }
            }
        }

        return answer;
    }
}

 

분석

  • 정확성 테스트도 중요하지만 효율성 테스트를 통과해야 한다.
  • O(N^2)을 O(N)으로 바꾸는게 중요해 보인다.

 

정답 (시간 초과 해결)

import java.util.*;
import java.util.stream.*;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {

        report = Arrays.stream(report).distinct().toArray(String[]::new);

        Map<String, Integer> siMap = new HashMap<>();
        Map<String, Boolean> sbMap = new HashMap<>();

        for(String str : report){
            String[] arr = str.split(" ");
            siMap.put(arr[1], siMap.getOrDefault(arr[1], 0) +1);

            if(siMap.get(arr[1]) >= k){
                sbMap.put(arr[1], true);
            }
        }

        int len = id_list.length;

        Map<String, Integer> siMap2 = new HashMap<>();
        for(int i=0; i<len; i++){
            siMap2.put(id_list[i], i);
        }

        int[] a = new int[len];

        for(String str : report){
            String[] arr = str.split(" ");
            if(sbMap.getOrDefault(arr[1], false)){
                a[siMap2.get(arr[0])]++;
            }
        }

        return a;
    }
}

 

분석

  • stream을 사용하는데 set을 굳이 한번 더 for문 돌릴 이유가 없어서 distinct()를 추가하였다.
  • list를 사용해서 풀면 이중 for문을 사용할 수 밖에 없는 구조이기 때문에 HashMap을 사용하여 O(1)방식을 사용하고
    for문을 사용하여 최종적으로 O(N) 방식으로 해결하였다.

 

참고할 만한 정답

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
        List<String> list = Arrays.stream(report).distinct().collect(Collectors.toList());
        HashMap<String, Integer> count = new HashMap<>();
        for (String s : list) {
            String target = s.split(" ")[1];
            count.put(target, count.getOrDefault(target, 0) + 1);
        }

        return Arrays.stream(id_list).map(_user -> {
            final String user = _user;
            List<String> reportList = list.stream().filter(s -> s.startsWith(user + " ")).collect(Collectors.toList());
            return reportList.stream().filter(s -> count.getOrDefault(s.split(" ")[1], 0) >= k).count();
        }).mapToInt(Long::intValue).toArray();
    }
}

 

비교 분석

  • 위 코드는 최대한 stream으로 해결한 코드로 보인다.
  • Stream을 사용하여 primitive type의 for문 속도 장점은 사라져서 굳이 배열로 변환하지 않고 List를 사용한 것으로 보인다.
  • return 부분에서 하나의 스트림으로 처리하려고 한 것 같은데
    stream 내부에 다시 stream을 사용하여 이중 반복이 된 것은 아닌지 의문이 생긴다.
반응형