|

모노톤 큐란 무엇인가: 슬라이딩 윈도우 최댓값 문제에서 왜 deque가 다시 등장할까

모노톤 큐란 무엇인가: 슬라이딩 윈도우 최댓값 문제에서 왜 deque가 다시 등장할까
모노톤 큐는 현재 구간의 최댓값 후보만 남기고 불필요한 값은 미리 제거한다

모노톤 큐는 deque를 배운 뒤 한 번 더 넘어야 하는 심화 감각입니다. 단순히 앞뒤에서 넣고 빼는 구조를 아는 것만으로는 부족하고, 현재 구간에서 의미 있는 후보만 남겨야 하기 때문입니다.

이번 글에서는 모노톤 큐를 공식처럼 소개하지 않고, 슬라이딩 윈도우 최댓값 후보를 버리지 않고 잘 추려 남기는 구조로 설명하겠습니다. 특히 왜 deque를 쓰면서도 일반 deque 문제와 사고방식이 달라지는지까지 같이 보겠습니다.

모노톤 큐 핵심 카드
핵심 판단 기준을 먼저 잡는 요약 카드

기술적 개념 참고로는 cp-algorithms의 queue modification 설명을 볼 수 있습니다. 하지만 실전에서는 수식보다 후보를 언제 버리는지 감각이 더 중요합니다.

왜 일반 deque만으로는 부족할까

입문자가 많이 헷갈리는 지점은 deque를 쓴다는 사실만 보고 모노톤 큐도 그냥 양끝 삽입/삭제 문제라고 생각하는 것입니다. 하지만 모노톤 큐의 본질은 deque 연산 자체가 아니라, 후보를 정리하는 규칙을 유지하는 데 있습니다.

슬라이딩 윈도우 최댓값 문제에서는 단순히 현재 구간의 원소를 모두 들고 있는 것만으로는 부족합니다. 매번 최댓값을 다시 찾으면 결국 윈도우 크기만큼 다시 스캔해야 하므로 비효율적입니다.

즉 필요한 것은 현재 구간의 모든 원소가 아니라, 최댓값이 될 가능성이 있는 후보들입니다. 이 후보만 정리해서 들고 있으면 매번 전체를 다시 보지 않아도 됩니다.


모노톤 큐는 무엇을 유지하나

최댓값 문제 기준으로 보면, deque 안에는 값이 큰 순서가 유지되도록 후보를 넣습니다. 새로운 값이 들어올 때 뒤에 있는 더 작은 값들은 앞으로 최댓값이 될 수 없으므로 미리 제거합니다.

왜냐하면 더 늦게 들어온 값이 더 크다면, 더 먼저 들어온 작은 값은 남아 있어도 앞으로 그 큰 값을 이길 수 없기 때문입니다.

모노톤 큐 동작 흐름 그림
새 값이 들어올 때 뒤의 작은 후보를 정리하고, 앞에서는 만료된 후보를 제거하는 흐름
from collections import deque

def max_sliding_window(nums, k):
    dq = deque()  # index 저장
    result = []

    for i, x in enumerate(nums):
        while dq and nums[dq[-1]] <= x:
            dq.pop()
        dq.append(i)

        if dq[0] <= i - k:
            dq.popleft()

        if i >= k - 1:
            result.append(nums[dq[0]])

    return result

이 코드에서 핵심은 두 개의 while/if입니다. 뒤에서는 현재 값보다 작거나 같은 후보를 제거하고, 앞에서는 현재 윈도우 범위를 벗어난 후보를 제거합니다. 즉 뒤 정리는 “더 이상 쓸모없는 후보 제거”, 앞 정리는 “유효기간 지난 후보 제거”입니다.


이 부분은 실제 구현에서 특히 많이 틀립니다. 값만 저장해도 될 것처럼 보이지만, 슬라이딩 윈도우는 “지금 이 후보가 아직 구간 안에 있는가”를 계속 확인해야 하기 때문에 위치 정보가 빠지면 로직이 금방 흐려집니다.

모노톤 큐에서 인덱스 저장과 값 저장 비교 카드
왜 값보다 인덱스 저장이 실전 구현에서 더 안전한지 비교한 카드

왜 인덱스를 저장하나

값만 저장하면 현재 후보가 윈도우 범위를 벗어났는지 판단하기 어렵습니다. 인덱스를 저장하면 dq[0]이 현재 윈도우 왼쪽 경계보다 작은지 쉽게 확인할 수 있습니다.

즉 모노톤 큐는 값 정렬 구조이면서 동시에 윈도우 경계 체크 구조이기도 합니다. 이 두 역할이 같이 있어야 완성됩니다.


어디서 가장 많이 헷갈릴까

  1. 왜 뒤의 작은 값을 미리 버려도 되는지
  2. 왜 값이 아니라 인덱스를 저장하는지
  3. 앞에서 제거하는 조건과 뒤에서 제거하는 조건이 왜 다른지
  4. 일반 deque 문제와 모노톤 큐 문제를 같은 것으로 보는 오해

특히 첫 번째가 중요합니다. 뒤에서 제거되는 작은 값은 더 늦게 들어온 더 큰 값 때문에 이미 최댓값 경쟁에서 졌다고 보면 됩니다.

기본 deque 감각은 큐와 덱 글, 윈도우 감각은 슬라이딩 윈도우 글과도 연결됩니다.


모노톤 큐 단계 추적 그림
현재 값이 들어올 때 후보가 어떻게 정리되는지 단계별로 보여주는 도식
모노톤 큐 오해 비교 카드
자주 하는 실수와 올바른 이해를 비교한 카드

실전 입력으로 한 번 따라가 보자

예를 들어 nums = [1, 3, -1, -3, 5], k = 3 이라고 해봅시다. 여기서 핵심은 매 순간 현재 윈도우의 최댓값 후보만 앞에 남기는 것입니다. 그래서 5가 들어오는 시점에는 그보다 작은 예전 후보들이 한꺼번에 뒤에서 밀려납니다.

이 흐름을 실제로 따라가 보면, 모노톤 큐는 복잡한 수학 구조라기보다 “최댓값 후보 선별 규칙을 가진 deque”에 가깝다는 감각이 생깁니다.

모노톤 큐 실전 윈도우 추적 예시 카드
작은 예시 입력으로 후보가 어떻게 교체되는지 요약한 카드

마무리

모노톤 큐의 핵심은 deque를 쓰는 것 자체가 아니라, 현재 구간에서 의미 있는 최댓값 후보만 남기도록 정리하는 데 있습니다.

뒤에서는 경쟁에서 진 후보를 버리고, 앞에서는 범위를 벗어난 후보를 버린다는 두 규칙을 이해하면 모노톤 큐가 훨씬 자연스럽게 보입니다.

함께보면 좋은 글