프로그래머스
2020 카카오 인턴십 - 보석쇼핑 java
호종이
2022. 2. 10. 13:23
코딩테스트 연습 - 보석 쇼핑
["DIA", "RUBY", "RUBY", "DIA", "DIA", "EMERALD", "SAPPHIRE", "DIA"] [3, 7]
programmers.co.kr
1. 보석의 가짓수를 찾기
모든 종류의 보석을 포함하는 구간을 찾아야 한다. 따라서 일단 보석 배열을 순차탐색해서, 보석이 총 몇 가지 종류로 이루어져 있는지를 찾아야 한다. 간단히 HashMap 을 이용해서 보석의 총 가지수를 구했다.
int jeweleryCount = 0;
public void getJeweleryCount(String[] gems) {
HashMap<String, Boolean> hashMap = new HashMap<>();
for (String gem : gems) {
if (!hashMap.containsKey(gem)) {
jeweleryCount++;
hashMap.put(gem, false);
}
}
}
2. 가장 짧은 구간 찾기
슬라이딩 윈도우를 활용하여 모든 보석을 포함하는 구간을 찾을 수 있다. 일단 가장 먼저 (0,0) 구간을 슬라이딩 윈도우의 시작 범위로 잡는다.
그 다음 슬라이딩 윈도우가 모든 보석을 포함하도록, 윈도우를 한 칸씩 늘려간다.
public int[] getAnswer(String[] gems) {
int[] ret = new int[2]; //반환 구간
HashMap<String, Integer> hashMap = new HashMap<>();
int count = 1;
ret[1] = 999999;
int start = 0;
int end = 0;
hashMap.put(gems[0], 1);
//가장 먼저 슬라이딩 윈도우가 모든 보석을 포함하도록 확장한다.
while (count < jeweleryCount && end < gems.length - 1) {
//윈도우를 오른쪽으로 확장해가며, 보석을 추가한다.
end++;
//윈도우가 해당 보석을 포함하지 않고 있으면 보석 종류 추가
if (!hashMap.containsKey(gems[end]) || hashMap.get(gems[end]) == 0) {
count++;
hashMap.put(gems[end], 1);
}
//윈도우가 해당 보석을 포함할 시
else {
hashMap.put(gems[end], hashMap.get(gems[end]) + 1);
}
}
}
슬라이딩 윈도우가 모든 보석을 포함하도록 초기화했으면, 이제 범위를 점차 좁히면 된다.
1. 슬라이딩 윈도우의 시작 부분을 start 라고 했을 때, start에 해당하는 보석을 뺐을 때 모든 보석을 포함하지 않으면 윈도우의 끝을 확장시킨다.
2. 만약 start 보석을 뻈을 때도 모든 보석을 포함하면 해당 보석을 빼고, start 를 1 증가시킨다.
while (true) {
if (end - start < ret[1] - ret[0]) {
ret[0] = start;
ret[1] = end;
}
//만약 왼쪽 보석을 뺏을 때 모든 보석을 포함하지 않으면
if (hashMap.get(gems[start]) - 1 == 0) {
//윈도우를 오른쪽으로 확장할 수 있을 때
if (end < gems.length - 1) {
end++;
hashMap.put(gems[end], hashMap.get(gems[end]) + 1);
}
//더 이상 오른쪽으로 확장할 수 없으면 바로 탈출
else {
break;
}
}
//왼쪽 보석을 빼도 모든 보석을 포함하면
else {
hashMap.put(gems[start], hashMap.get(gems[start]) - 1);
start++;
}
}
이 때 슬라이딩 윈도우는 항상 모든 보석을 포함하고 있으므로, 가장 짧거나, 왼쪽에 있는 범위로 계속해서 갱신시켜준다.
전체 코드
package per.jongho;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
public class JewelryShopping {
int jeweleryCount = 0;
public static void main(String[] args) throws IOException {
JewelryShopping jewelryShopping = new JewelryShopping();
String[] gems = {"ZZZ", "YYY", "NNNN", "YYY", "BBB"};
System.out.println(Arrays.toString(jewelryShopping.solution(gems)));
}
public int[] solution(String[] gems) {
getJeweleryCount(gems);
return getAnswer(gems);
}
public int[] getAnswer(String[] gems) {
int[] ret = new int[2]; //반환 구간
HashMap<String, Integer> hashMap = new HashMap<>();
int count = 1;
ret[1] = 999999;
int start = 0;
int end = 0;
hashMap.put(gems[0], 1);
//가장 먼저 슬라이딩 윈도우가 모든 보석을 포함하도록 확장한다.
while (count < jeweleryCount && end < gems.length - 1) {
end++;
if (!hashMap.containsKey(gems[end]) || hashMap.get(gems[end]) == 0) {
count++;
hashMap.put(gems[end], 1);
} else {
hashMap.put(gems[end], hashMap.get(gems[end]) + 1);
}
}
while (true) {
if (end - start < ret[1] - ret[0]) {
ret[0] = start;
ret[1] = end;
}
//만약 왼쪽 보석을 뺏을 때 모든 보석을 포함하지 않으면
if (hashMap.get(gems[start]) - 1 == 0) {
//윈도우를 오른쪽으로 확장할 수 있을 때
if (end < gems.length - 1) {
end++;
hashMap.put(gems[end], hashMap.get(gems[end]) + 1);
}
//더 이상 오른쪽으로 확장할 수 없으면 바로 탈출
else {
break;
}
}
//왼쪽 보석을 빼도 모든 보석을 포함하면
else {
hashMap.put(gems[start], hashMap.get(gems[start]) - 1);
start++;
}
}
ret[0]++;
ret[1]++;
return ret;
}
public void getJeweleryCount(String[] gems) {
HashMap<String, Boolean> hashMap = new HashMap<>();
for (String gem : gems) {
if (!hashMap.containsKey(gem)) {
jeweleryCount++;
hashMap.put(gem, false);
}
}
}
}