첫번째 시도
1. 단어들에 대해서 길이에 따른 해시맵 생성
2. 뒤집은 단어들을 길이에 따라 해시맵 생성
3. 쿼리마다 ?로 시작하는지 여부에 따라 첫번째 해시맵 또는 두번째 해시맵 불러온다.
4. 불러온 List에서 ?를 제외한 쿼리로 시작하는 단어의 개수를 구한다.
문제점
4번에서 모든 단어들을 하나씩 불러오기에는 시간복잡도에 문제가 생긴다.
두번째 시도
- 단어들에 대해서 길이에 따른 해시맵 생성
- 뒤집은 단어들을 길이에 따라 해시맵 생성
- 해시맵 정렬
- 쿼리마다 ?로 시작하는지 여부에 따라 첫번째 해시맵 또는 두번째 해시맵 불러온다.
- ?를 a로 대체한 String, z로 대체한 String 두개 생성
- a로 대체한 String이 들어갈 위치와 z로 대체한 String이 들어갈 위치 구하고 차이로 범위안에 있는 String의 수를 구한다.
결론
- left_index, right_index 함수 암기
- compareTo 로 String 비교시 헷갈리지 않게 정리하자
1차 코드
import java.util.*;
class Solution {
public int[] solution(String[] words, String[] queries) {
int n = queries.length;
int[] answer = new int[n];
HashMap<Integer, List<String>> map = new HashMap<>();
HashMap<Integer, List<String>> re_map = new HashMap<>();
for(String word : words){
int len = word.length();
StringBuilder sb = new StringBuilder(word);
String re_word = sb.reverse().toString();
if(map.get(len) == null){
List<String> now = new ArrayList<>();
now.add(word);
map.put(len, now);
}
else{
List<String> now = map.get(len);
now.add(word);
map.put(len, now);
}
if(re_map.get(len) == null){
List<String> now = new ArrayList<>();
now.add(re_word);
re_map.put(len, now);
}
else{
List<String> now = re_map.get(len);
now.add(re_word);
re_map.put(len, now);
}
}
for(int i=0; i<n; i++){
String query = queries[i];
int len = query.length();
if(query.charAt(0) == '?'){
List<String> check = re_map.get(len);
if(check == null){
continue;
}
StringBuilder value = new StringBuilder();
for(int j=len-1; j>=0; j--){
char c = query.charAt(j);
if(c == '?'){
break;
}
value.append(c);
}
String result = value.toString();
for(String now : check){
if(now.startsWith(result)){
answer[i] += 1;
}
}
}
else{
List<String> check = map.get(len);
if(check == null){
continue;
}
StringBuilder value = new StringBuilder();
for(char c : query.toCharArray()){
if(c == '?'){
break;
}
value.append(c);
}
String result = value.toString();
for(String now : check){
if(now.startsWith(result)){
answer[i] += 1;
}
}
}
}
return answer;
}
}
2차 코드
import java.util.*;
class Solution {
public int[] solution(String[] words, String[] queries) {
// 정답 배열
int n = queries.length;
int[] answer = new int[n];
// 길이별 해시 함수 만들기
HashMap<Integer, List<String>> or_map = new HashMap<>();
HashMap<Integer, List<String>> re_map = new HashMap<>();
for(String word : words){
int len = word.length();
if(or_map.get(len) == null){
List<String> now = new ArrayList<>();
now.add(word);
or_map.put(len, now);
}
else{
List<String> now = or_map.get(len);
now.add(word);
or_map.put(len, now);
}
StringBuilder sb = new StringBuilder(word);
String re_word = sb.reverse().toString();
if(re_map.get(len) == null){
List<String> now = new ArrayList<>();
now.add(re_word);
re_map.put(len, now);
}
else{
List<String> now = re_map.get(len);
now.add(re_word);
re_map.put(len, now);
}
}
// 정렬
for(int key : or_map.keySet()){
List<String> values1 = or_map.get(key);
List<String> values2 = re_map.get(key);
Collections.sort(values1);
Collections.sort(values2);
or_map.put(key, values1);
re_map.put(key, values2);
}
// 메인로직
for(int i=0; i<n; i++){
String query = queries[i];
int len = query.length();
// ?로 시작하는 경우
if(query.charAt(0) != '?'){
String start = query.replace("?", "a");
String end = query.replace("?", "z");
List<String> array = or_map.get(len);
if(array == null){
continue;
}
answer[i] = find(array, start, end);
}
// ?로 시작하지 않는 경우
else{
StringBuilder sb = new StringBuilder(query);
String re_query = sb.reverse().toString();
String start = re_query.replace("?", "a");
String end = re_query.replace("?", "z");
List<String> array = re_map.get(len);
if(array == null){
continue;
}
answer[i] = find(array, start, end);
}
}
return answer;
}
public static int find(List<String> array, String start, String end){
int left = left_index(array, start);
int right = right_index(array, end);
return right-left;
}
public static int right_index(List<String> arr, String target){
int start = 0;
int end = arr.size();
while(start<end){
int mid = (start+end)/2;
String value = arr.get(mid);
// arr[mid]가 target보다 사전순으로 같거나 뒤에 있다면
if(value.compareTo(target) >= 0){
end = mid;
}
else{
start = mid+1;
}
}
return end;
}
public static int left_index(List<String> arr, String target){
int start = 0;
int end = arr.size();
int result = 0;
while(start<end){
int mid = (start+end)/2;
String value = arr.get(mid);
// arr[mid]가 target보다 사전순으로 뒤에 있다면
if(value.compareTo(target) > 0){
end = mid;
}
else{
start = mid+1;
}
}
return end;
}
}
'Algorithm > Practice' 카테고리의 다른 글
이코테 - 퇴사 with JAVA (0) | 2023.09.13 |
---|---|
이코테 - 효율적인 화폐 구성 with JAVA (0) | 2023.09.12 |
이코테 - 공유기 설치 with JAVA (0) | 2023.09.06 |
이코테 - 정렬된 배열에서 특정 수의 개수 구하기 (0) | 2023.09.05 |
이코테 - 안테나 with JAVA (0) | 2023.09.04 |