슬라이딩 윈도우
배열이나 문자열에서 일정 범위(윈도우)를 유지한 채 양 끝을 같은 방향으로 이동시키며, 매번 윈도우를 처음부터 다시 계산하지 않고 이전 결과를 재사용해 갱신하는 기법입니다.
동작 과정
고정 크기 윈도우: 길이 3인 부분배열의 최대 합
A = [2, 1, 5, 1, 3, 2] k = 3
[2,1,5] 1 3 2 sum=8 → max=8
2 [1,5,1] 3 2 sum=8-2+1=7
2 1 [5,1,3] 2 sum=7-1+3=9 → max=9
2 1 5 [1,3,2] sum=9-5+2=6
답 = 9
가변 크기 윈도우: 중복 없는 최장 부분 문자열
s = "abcabcbb"
right=0 'a' → window=[a] 길이1 → max=1
right=1 'b' → window=[a,b] 길이2 → max=2
right=2 'c' → window=[a,b,c] 길이3 → max=3
right=3 'a' → 중복! left를 이전 'a' 다음으로 이동
→ window=[b,c,a] (left=1) 길이3 → max=3
right=4 'b' → 중복! left를 이전 'b' 다음으로 이동
→ window=[c,a,b] (left=2) 길이3
답 = 3
두 예시 모두 left, right 두 경계가 항상 같은 방향으로만 전진하고 되돌아가지 않습니다. 양 끝에서 좁혀 들어가는 투 포인터와 달리, 슬라이딩 윈도우는 구간(창) 자체를 유지한 채 미끄러뜨린다는 점이 다릅니다.
구현
// 고정 크기 윈도우: 길이 k인 부분배열의 최대 합
int maxSumFixedWindow(int[] a, int k) {
int sum = 0;
for (int i = 0; i < k; i++) {
sum += a[i];
}
int max = sum;
for (int right = k; right < a.length; right++) {
sum += a[right] - a[right - k];
max = Math.max(max, sum);
}
return max;
}
// 가변 크기 윈도우: 중복 없는 최장 부분 문자열
int longestUniqueSubstring(String s) {
Map<Character, Integer> lastSeen = new HashMap<>();
int left = 0, max = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
if (lastSeen.containsKey(c) && lastSeen.get(c) >= left) {
left = lastSeen.get(c) + 1;
}
lastSeen.put(c, right);
max = Math.max(max, right - left + 1);
}
return max;
}
복잡도
| 구분 | 복잡도 | 근거 |
|---|---|---|
| 시간 | O(N) | right가 한 번씩 전진하고, left도 전체 구간에서 합쳐 최대 N번만 전진 |
| 공간 | O(1) ~ O(K) | 고정 윈도우는 합만 유지하면 O(1), 중복 판별에 HashMap을 쓰면 윈도우 안 원소 수만큼 O(K) |
매 윈도우를 처음부터 다시 합산하거나 스캔하면 O(N·K)가 되는데, 이전 윈도우의 결과에서 빠지는 원소만 빼고 들어오는 원소만 더해 갱신하므로 O(N)으로 줄어듭니다.
주의사항
- 고정 vs 가변 구분이 먼저다: 윈도우 크기가 문제에서 고정으로 주어지는지, 조건(중복 없음, 합이 특정 값 이하 등)에 따라 늘었다 줄었다 하는지를 먼저 판단해야 접근 방식이 정해진다
- 가변 윈도우에서
left를 당기는 조건을 while로 명확히 표현해야 한다: if로 한 번만 처리하면 조건을 여전히 어기는 상태로 윈도우가 남을 수 있다 - 중복 문자 판별처럼 "마지막으로 본 위치"가 필요한 경우
lastSeen.get(c) >= left조건을 빼먹으면, 이미 윈도우 밖으로 나간 문자 때문에left가 잘못 앞으로 당겨질 수 있다 - 단조성 전제:
right가 전진하면서 조건이 나빠지는 방향으로만 움직인다는 보장이 있어야,left를 다시 뒤로 되돌리지 않고 한 방향으로만 이동시켜도 정답이 보장된다
핵심 정리
- 배열/문자열에서 구간(창)을 유지하며 양 끝을 같은 방향으로만 이동시켜 O(N)에 답을 구하는 기법
- 고정 크기면 "진입 원소 추가, 이탈 원소 제거"만으로 갱신하고, 가변 크기면 조건을 어길 때마다
left를 당긴다 - 같은 방향으로만 이동한다는 점에서 투 포인터의 한 갈래로 볼 수 있지만, 양 끝에서 좁혀 들어가는 투 포인터와는 구분된다