1,2만 존재하는 수열이 있다.
이 때, 연속된 구간 중 1이 K개 이상 있는 배열 중 가장 짧은 길이를 구하는 것이 문제이다.
1이 K개 이상 있는 배열을 구하는 문제이다.
1이 몇 번 나왔는지에 따라 배열의 길이를 줄일지, 혹은 늘릴지 결정할 수 있을 것이다.
우리는 left, right 포인터를 설정할 것이고, 초기 위치는 index = 0위치이다.
그리고 두 포인터는 아래와 같은 조건 때 움직인다.
left : 구간에 1이 K개 나왔다면, 오른쪽으로 이동한다. 이 때 한 칸만 이동하는 것이 아닌, 다시 arr[left] = 1이 되는 구간까지 증가시켜야 한다.
right : 구간에 1이 K개 미만으로 나왔다면, 오른쪽으로 이동한다. 이 때 한 칸만 이동하는 것이 아닌 arr[right] = 1이 되는 구간까지 증가시켜야 한다.
left, right의 이동에 대해서 조금 더 자세히 알아보자.
1 2 1 2 1이라는 수가 있다고 생각하자.
만약, right = 4이고, left = 0 이였을 때 left를 1 증가시켜야 하는 경우이다.
하지만, 2 1 2 1이든 1 2 1이든 1이 2번 나오는 것은 동일하다.
우리는 최소의 구간 길이를 구하고 싶기 때문에 1 2 1이 답이 될 것이다.
즉, 최소의 구간 길이는 "시작" 부분도 1이고, "종료" 부분도 1인 구간의 길이가 될 것이다.
따라서 index = 2인 곳까지 이동시킨 후 알고리즘을 수행한다.
right도 동일한 이유로 arr[right] = 1이 되는 구간까지 이동시켜 줘야 한다.
마지막으로, right이 배열의 끝을 가리키고 있더라도 left는 아직 움직일 수 있다. 따라서 while문을 추가시켜주어 가능한 최대로 left를 오른쪽으로 이동시켜줄 필요가 있다.
import java.io.*;
import java.util.*;
public class Main {
static int N, K;
static Integer[] arr;
static int[] alpha = new int[26];
static void two_pointer() {
int left = 0;
int right = 0;
int sum = 0;
int length = Integer.MAX_VALUE;
while(right < N) {
if(sum<K) {
if(arr[right]==1) {
/*
arr[right] = 1이 될 때 까지는 계속 right++만 수행될 것이다.
arr[right] = 1이 된 순간 연속된 배열에 1이 1개 추가된 것이므로
sum을 1증가시킨다.
*/
sum++;
}
right++;
}
else {
/*
arr[left] = 1이 될 때 까지는 계속 left++만 수행될 것이다.
arr[left] = 1이 된 순간, 연속된 배열에 1이 1개 빠지므로,
sum을 1 감소시킨다.
또한, sum >= K인 상황이므로, 정답이 될 가능성이 있는 후보이다.
따라서 원래 저장되어 있던 길이와 이 길이를 비교하여
작은 값으로 갱신한다.
*/
if(arr[left]==1) {
length = Math.min(length,right - left);
sum--;
}
left++;
}
}
while(left < N) {
if(sum<K) break;
if(arr[left]==1) {
length = Math.min(length,right - left);
sum--;
}
left++;
}
if(length==Integer.MAX_VALUE) System.out.println(-1);
else System.out.println(length);
}
public static void main(String[] args) {
FastReader sc = new FastReader();
N = sc.nextInt();
K = sc.nextInt();
arr= new Integer[N];
for(int i =0;i<N;i++) {
arr[i] = sc.nextInt();
}
two_pointer();
}
static class FastReader // 빠른 입력을 위한 클래스
}