단순 슬라이딩 윈도우로는 구간 내 최솟값을 에 찾을 수 없습니다. 우리는 덱(Deque)을 이용해 '최솟값이 될 가능성이 있는 후보'들만 오름차순으로 유지하는 전략을 사용합니다.
peekFirst) 노드의 인덱스가 현재 범위를 벗어났다면(i - idx >= L) 제거합니다.import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
// 모노톤 덱 + 슬라이딩 윈도우 최적화 풀이
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))) {
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int L = Integer.parseInt(st.nextToken());
st = new StringTokenizer(br.readLine());
StringBuilder sb = new StringBuilder();
Deque<Node> dq = new ArrayDeque<>();
for (int i = 0; i < N; i++) {
// [Optimization] 배열을 쓰지 않고 바로 Node 객체 생성 및 처리
int now = Integer.parseInt(st.nextToken());
Node node = new Node(i, now);
// 1. 윈도우 범위를 벗어난 인덱스 제거 (O(1))
if (!dq.isEmpty() && i - dq.peekFirst().idx >= L) {
dq.pollFirst();
}
// 2. 현재 값보다 큰 이전 후보들 제거 (Monotonic Property 유지)
// '나보다 크면서 나보다 먼저 들어온 애들'은 가차없이 삭제
while (!dq.isEmpty() && dq.peekLast().val >= node.val) {
dq.pollLast();
}
dq.addLast(node);
// 3. 덱의 맨 앞은 항상 현재 구간의 최솟값
sb.append(dq.peekFirst().val).append(" ");
// 중간 출력 최적화 (출력 버퍼 관리)
if (i % 10000 == 0) {
bw.write(sb.toString());
sb.setLength(0);
}
}
bw.write(sb.toString());
bw.append("\n").flush();
}
}
static class Node {
int idx, val;
Node(int idx, int val) {
this.idx = idx;
this.val = val;
}
}
}
int 배열은 약 20MB를 차지합니다. 배열 없이 처리하면 덱에 들어있는 최대 개의 노드만 메모리에 유지하면 되므로 훨씬 효율적입니다.이번 문제는 슬라이딩 윈도우와 단조 큐(Monotonic Queue)의 결합을 보여주는 정석적인 사례였습니다. 특히 대량의 데이터를 다룰 때는 알고리즘의 시간 복잡도()뿐만 아니라, 불필요한 자료구조 선언을 줄이는 공간 최적화 능력이 얼마나 중요한지 배울 수 있었습니다.