본문으로 건너뛰기
김신건의 로그

스택 (Stack)

· 수정 · 📖 약 3분 · 935자/단어 #algorithm #data-structure #stack
stack, 스택, LIFO, 단조 스택, monotonic stack

정의

스택 (Stack)LIFO (Last In, First Out) 순서로 원소를 관리하는 추상 자료구조입니다. push(x), pop(), top() 세 연산만 제공하며, 가장 최근 삽입된 원소만 접근 가능합니다.

C++ STL std::stack, Python list, Java Stack / ArrayDeque 로 기본 제공됩니다.

문제 상황과 동기

함수 호출, 괄호 매칭, DFS 구현, 수식 파싱 등 “가장 최근 상태로 되돌아가야 하는” 모든 문제에서 스택이 자연스럽게 등장합니다.

  • naive: 배열 전체를 순회하며 “최근 값” 을 찾으면 O(N²).
  • stack: 최근 값만 O(1) 접근. push/pop 도 O(1).

핵심 통찰: 재귀 = 시스템 스택, 모든 DFS / backtracking 은 스택 기반. 명시적 스택을 쓰면 재귀 깊이 제한 (Python 기본 1000) 을 피할 수 있습니다.

시각화

핵심 아이디어

invariant: top 은 항상 가장 최근 삽입 원소. 삽입 / 삭제 순서가 역순.

단조 스택 (Monotonic Stack)

스택 내부를 오름차순 / 내림차순으로 유지하면서 push. 새 원소가 들어올 때, 조건 위배되는 top 을 pop. “다음 큰 원소 (Next Greater Element)” 같은 문제를 O(N) 에 해결.

for each x in array:
    while stack not empty and stack.top < x:
        stack.pop()   # top 이 x 보다 작으면 제거
    stack.push(x)

스택에 남은 원소들은 감소 수열. 각 원소는 최대 1번 push + 1번 pop, amortized O(1).

알고리즘

기본 스택 (배열 구현)

class Stack:
    data = []
    size = 0

    push(x):
        data[size++] = x

    pop():
        return data[--size]

    top():
        return data[size - 1]

    empty():
        return size == 0

단조 스택 (Next Greater Element)

next_greater(a):
    result = array of length N, fill with -1
    stack = empty
    for i = 0..N-1:
        while stack not empty and a[stack.top] < a[i]:
            idx = stack.pop()
            result[idx] = a[i]
        stack.push(i)
    return result

구현

// 괄호 매칭 (valid parentheses)
#include <bits/stdc++.h>
using namespace std;
int main() {
  string s; cin >> s;
  stack<char> st;
  for (char c : s) {
      if (c == '(' || c == '[' || c == '{') {
          st.push(c);
      } else {
          if (st.empty()) { cout << "NO\n"; return 0; }
          char t = st.top(); st.pop();
          if (c == ')' && t != '(') { cout << "NO\n"; return 0; }
          if (c == ']' && t != '[') { cout << "NO\n"; return 0; }
          if (c == '}' && t != '{') { cout << "NO\n"; return 0; }
      }
  }
  cout << (st.empty() ? "YES" : "NO") << "\n";
}
stdin
()[]{}
결과
YES

단조 스택 예제 (Next Greater Element)

// 각 원소의 오른쪽에서 가장 가까운 큰 값
#include <bits/stdc++.h>
using namespace std;
int main() {
  int n; cin >> n;
  vector<int> a(n), res(n, -1);
  for (auto& v : a) cin >> v;
  stack<int> st;
  for (int i = 0; i < n; i++) {
      while (!st.empty() && a[st.top()] < a[i]) {
          res[st.top()] = a[i];
          st.pop();
      }
      st.push(i);
  }
  for (int v : res) cout << v << " ";
  cout << "\n";
}
stdin
6
2 1 2 4 3 5
결과
4 2 4 5 5 -1

복잡도

항목
pushO(1)
popO(1)
topO(1)
공간O(N)
단조 스택 (전체)O(N) - 각 원소 최대 1번 push + 1번 pop

변형 / 활용

패턴설명예제
괄호 매칭여는 괄호는 push, 닫는 괄호는 pop + 매칭BOJ 4949
단조 증가 스택top < x 인 동안 pop, 다음 큰 원소BOJ 2493, 17298
단조 감소 스택top > x 인 동안 pop, 다음 작은 원소히스토그램 면적
수식 파싱infix → postfix. 연산자 우선순위 관리계산기 구현
DFS 명시 스택재귀 대신 while + stack. 깊이 제한 우회트리 순회
백트래킹 상태각 분기마다 스택에 상태 저장N-Queen, 미로

함정

1. pop() 전 empty 체크

스택이 비었는데 pop 하면 런타임 에러 (C++, Java) 또는 IndexError (Python).

if (!st.empty()) st.pop();   // 항상 확인

2. top() 도 empty 체크 필요

if (!st.empty()) cout << st.top();

3. 단조 스택 조건 방향

“다음 큰 원소” 는 a[st.top()] < a[i] 일 때 pop. “다음 작은 원소” 는 a[st.top()] > a[i]. 부등호 방향 주의.

4. 인덱스 vs 값

단조 스택에 값을 넣으면 나중에 원래 위치를 찾을 수 없습니다. 인덱스를 저장하고, a[st.top()] 로 값 접근.

5. Java Stack 대신 Deque

Java Stack 은 레거시 클래스 (Vector 기반, synchronized). ArrayDeque 가 더 빠릅니다.

Deque<Integer> st = new ArrayDeque<>();
st.push(x); st.pop(); st.peek();

BOJ 연습 문제

번호제목정답률링크
BOJ 10828스택-kokoa-lab
BOJ 4949균형잡힌 세상-kokoa-lab
BOJ 17298오큰수-kokoa-lab
BOJ 2493-kokoa-lab
BOJ 6198옥상 정원 꾸미기-kokoa-lab

참고

이 글의 용어 (3개)
깊이 우선 탐색 (DFS)algorithm
정의 깊이 우선 탐색 (Depth-First Search, DFS) 는 그래프 G=(V, E) 에서 갈 수 있는 만큼 깊이 들어가다가 막히면 백트래킹하는 알고리즘. 스택 (LIF…
재귀 (Recursion)algorithm
정의 재귀 (Recursion) 는 함수가 자기 자신을 호출하는 프로그래밍 기법. base case (종료 조건) 와 recursive case (재귀 단계) 로 구성되며, 복잡…
큐 (Queue)algorithm
정의 큐 (Queue) 는 FIFO (First In, First Out) 순서로 원소를 관리하는 추상 자료구조입니다. (또는 ), (또는 ), 세 연산만 제공하며, 가장 먼저 …

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기