https://programmers.co.kr/learn/courses/30/lessons/72412
문제 풀이 이 문제는 그냥 문자열대 문자열로 부딪히게 되면 시간 초과가 날 수 밖에 없는 문제다. 선형적으로 풀면 info 배열의 최대 크기는 5만, query 배열의 최대 크기는 10만 이므로 최대 50억 연산을 하게 되므로 효율성 측면에서 문제가 생긴다. 결국 이 문제는 어떤 방법을 이용해 검색할 것인가가 가장 큰 관건이 된다. 선형적인 탐색을 하는 방법이 아닌 O(logn)의 시간 복잡도를 갖는 자료구조 혹은 탐색 기법을 이용하는 방법으로 문제를 접근해야 한다. 동시에 만들 수 있는 문장의 경우의 수를 고려해줘야 한다. 복합적인 문제라 쉽지 않다.
처음에 각 문자열내 문자들을 파싱해서 map에다가 저장을 해야 하나?…. 그러면 탐색을 어떻게 해야하지?… 하면서 문제 접근을 못하다가 다른 분 풀이를 살짝 참고 했는데 문자열 자체를 map의 key값으로 넣는 것을 보고 힌트를 얻어 문제를 접근할 수 있었다.
info 내 문자열을 정재해 띄어쓰기는 문장을 만들어준다.
key로 정재된 문장을 value로는 같은 key를 갖는 문장에 대한 값들을 보관하기 위해 List형태로 넣어준다.
info 내 문장들이 map으로 다 들어갔으면 Binary Search를 사용하기 위해 오름 차순으로 정렬 해준다.
query 내 문자열을 정재해 준다.
info에서 구분자는 띄어쓰기 였지만 query에서 구분자는 and와 띄어쓰기다.
‘-‘를 만나게 되면 만들 수 있는 문장의 모든 경우의 수를 만들어준다.
정재된 문자를 갖고 info에 값이 있는지 확인한다.
값이 있으면 List에서 query에서 요구하는 값 이상이 되는 사람 수를 찾는다.(Lower Bound)
쿼리가 여러개인 경우는 각각의 경우들을 모두 찾아서 더해준다.
찾은 결과를 answer에 넣어 반환한다.
info 내 문자열을 정재하기 public void infoToMap (String[] info) { for (int i = 0 ; i < info.length; i++) { String[] words = info[i].split(" " ); StringBuilder sb = new StringBuilder (); int score = Integer.parseInt(words[words.length - 1 ]); for (int j = 0 ; j < words.length - 1 ; j++) { sb.append(words[j]); } String key = sb.toString(); infos.computeIfAbsent(key, k -> new ArrayList <>()).add(score); } }
map 내 List값들을 오름차순으로 정렬하기 infos.forEach((key, value) -> { value.sort(null ); });
query 내 문자열 정재하고 모든 경우의 수 만들기 ‘-‘는 모든 조건을 허용한다는 의미이므로 조건에 해당하는 모든 경우의 수를 만들어 주도록 한다.
String[] words = query[i].split(" and | " ); ArrayList<String> qu = new ArrayList <>(); qu.add("" ); for (int j = 0 ; j < words.length - 1 ; j++) { int arrSize = qu.size(); for (int aIndex = 0 ; aIndex < arrSize; aIndex++) { String subStr = qu.get(aIndex); if (words[j].equals("-" )) { if (j == 0 ) { qu.set(aIndex, subStr + "cpp" ); qu.add(subStr + "java" ); qu.add(subStr + "python" ); } else if (j == 1 ) { qu.set(aIndex, subStr + "backend" ); qu.add(subStr + "frontend" ); } else if (j == 2 ) { qu.set(aIndex, subStr + "junior" ); qu.add(subStr + "senior" ); } else if (j == 3 ) { qu.set(aIndex, subStr + "chicken" ); qu.add(subStr + "pizza" ); } } else { qu.set(aIndex, subStr + words[j]); } } }
정재된 query 문자열을 이용해 qeury에서 요구하는 값 이상의 사람 수를 찾는다. public int binarySearch (List<Integer> list, int value) { int begin = 0 ; int end = list.size(); int mid = (begin + end) / 2 ; while (begin < end) { mid = (begin + end) / 2 ; if (value > list.get(mid)) { begin = mid + 1 ; } else { end = mid; } } return list.size() - begin; }
int num = 0 ;for (int j = 0 ; j < qu.size(); j++) { String key = qu.get(j).trim(); int value = Integer.parseInt(words[words.length - 1 ]); List<Integer> list = infos.getOrDefault(key, new ArrayList <>()); num += binarySearch(list, value); } answer[i] = num;
전체 소스 import java.util.*;import java.io.*;class Solution { Map<String, List<Integer>> infos = new HashMap <>(); public int binarySearch (List<Integer> list, int value) { int begin = 0 ; int end = list.size(); int mid = (begin + end) / 2 ; while (begin < end) { mid = (begin + end) / 2 ; if (value > list.get(mid)) { begin = mid + 1 ; } else { end = mid; } } return list.size() - begin; } public void infoToMap (String[] info) { for (int i = 0 ; i < info.length; i++) { String[] words = info[i].split(" " ); StringBuilder sb = new StringBuilder (); int score = Integer.parseInt(words[words.length - 1 ]); for (int j = 0 ; j < words.length - 1 ; j++) { sb.append(words[j]); } String key = sb.toString(); infos.computeIfAbsent(key, k -> new ArrayList <>()).add(score); } } public int [] solution(String[] info, String[] query) { int [] answer = new int [query.length]; infoToMap(info); infos.forEach((key, value) -> { value.sort(null ); }); for (int i = 0 ; i < query.length; i++) { String[] words = query[i].split(" and | " ); ArrayList<String> qu = new ArrayList <>(); qu.add("" ); for (int j = 0 ; j < words.length - 1 ; j++) { int arrSize = qu.size(); for (int aIndex = 0 ; aIndex < arrSize; aIndex++) { String subStr = qu.get(aIndex); if (words[j].equals("-" )) { if (j == 0 ) { qu.set(aIndex, subStr + "cpp" ); qu.add(subStr + "java" ); qu.add(subStr + "python" ); } else if (j == 1 ) { qu.set(aIndex, subStr + "backend" ); qu.add(subStr + "frontend" ); } else if (j == 2 ) { qu.set(aIndex, subStr + "junior" ); qu.add(subStr + "senior" ); } else if (j == 3 ) { qu.set(aIndex, subStr + "chicken" ); qu.add(subStr + "pizza" ); } } else { qu.set(aIndex, subStr + words[j]); } } } int num = 0 ; for (int j = 0 ; j < qu.size(); j++) { String key = qu.get(j).trim(); int value = Integer.parseInt(words[words.length - 1 ]); List<Integer> list = infos.getOrDefault(key, new ArrayList <>()); num += binarySearch(list, value); } answer[i] = num; } return answer; } }