Algorithm
프로그래머스
Java
순위 검색

순위 검색

https://school.programmers.co.kr/learn/courses/30/lessons/72412 (opens in a new tab)

내 풀이

Query와 Info를 하나씩 비교하면 반드시 시간초과가 난다.

class Solution {
    private HashMap<Integer, String[]> infoMap = new HashMap<>();
 
    public int[] solution(String[] info, String[] query) {
        List<Integer> ans = new ArrayList<>();
        // 모든 정보를 해시맵에 저장
        for (int i = 0; i < info.length; i++) {
            infoMap.put(i, info[i].split(" "));
        }
 
        for (String q : query) {
            String[] parsedQuery = q.replace("and ", "").split(" ");
            String lang = parsedQuery[0];
            String pos = parsedQuery[1];
            String car = parsedQuery[2];
            String food = parsedQuery[3];
            int point = Integer.parseInt(parsedQuery[4]);
 
            long count = infoMap.entrySet().stream()
                .filter(e -> {
                    String[] details = e.getValue();
                    return (lang.equals("-") || details[0].equals(lang)) &&
                           (pos.equals("-") || details[1].equals(pos)) &&
                           (car.equals("-") || details[2].equals(car)) &&
                           (food.equals("-") || details[3].equals(food)) &&
                           Integer.parseInt(details[4]) >= point;
                })
                .count();
 
            ans.add((int) count);
        }
 
        return ans.stream().mapToInt(Integer::intValue).toArray();
    }
}

정답 풀이

모든 경우의 수를 key 값으로 변경한다. 예를 들자면

java, backend, junior, pizza, 100 라면 key의 종류는 아래와 같이 총 16개가 된다.

  • -, -, -, -, 100
  • java, -, -, -, 100
  • java, backend, -, -, 100
  • java, backend, junior, -, 100
  • java, backend, junior, pizza, 100

...

  • -, backend, junior, -, 100
  • -, backend, -, -, 100

...

이 부분은 흔히 쓰이는 Combination 로직을 사용해서 구할 수 있다.

// info가 포함될 수 있는 문장
private static void makeSentence(String[] p, String str, int cnt) {
    if (cnt == 4) {
        if (!map.containsKey(str)) {
            List<Integer> list = new ArrayList<Integer>();
            map.put(str, list);
        }
        map.get(str).add(Integer.parseInt(p[4]));
        return;
    }
    makeSentence(p, str + "-", cnt + 1);
    makeSentence(p, str + p[cnt], cnt + 1);
}

그리고 이 Qeury를 각각 key로 만들고 점수를 이분 탐색을 해서 풀어야 효율성에 통과한다.

전체 코드
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
 
class Solution {
    static HashMap<String, List<Integer>> map;
 
    public static int[] solution(String[] info, String[] query) {
        int[] answer = new int[query.length];
        map = new HashMap<String, List<Integer>>();
 
        for (int i = 0; i < info.length; i++) {
            String[] p = info[i].split(" ");
            makeSentence(p, "", 0);
        }
 
        for (String key : map.keySet())
            Collections.sort(map.get(key));
 
        for (int i = 0; i < query.length; i++) {
            query[i] = query[i].replaceAll(" and ", "");
            String[] q = query[i].split(" ");
            answer[i] = map.containsKey(q[0]) ? binarySearch(q[0], Integer.parseInt(q[1])) : 0;
        }
 
        return answer;
    }
 
    // 이분 탐색
    private static int binarySearch(String key, int score) {
        List<Integer> list = map.get(key);
        int start = 0, end = list.size() - 1;
 
        while (start <= end) {
            int mid = (start + end) / 2;
            if (list.get(mid) < score)
                start = mid + 1;
            else
                end = mid - 1;
        }
 
        return list.size() - start;
    }
 
    // info가 포함될 수 있는 문장
    private static void makeSentence(String[] p, String str, int cnt) {
        if (cnt == 4) {
            if (!map.containsKey(str)) {
                List<Integer> list = new ArrayList<Integer>();
                map.put(str, list);
            }
            map.get(str).add(Integer.parseInt(p[4]));
            return;
        }
        makeSentence(p, str + "-", cnt + 1);
        makeSentence(p, str + p[cnt], cnt + 1);
    }
}

Reference