이번 문제는 LeetCode에서의 스택 자료 구조 유형 문제입니다. 살펴볼까요?
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Implement the MinStack
class:
MinStack()
initializes the stack object.void push(int val)
pushes the element val
onto the stack.void pop()
removes the element on the top of the stack.int top()
gets the top element of the stack.int getMin()
retrieves the minimum element in the stack.You must implement a solution with O(1)
time complexity for each function.
Example 1:
Input
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
Output
[null,null,null,null,-3,null,0,-2]
Explanation
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top(); // return 0
minStack.getMin(); // return -2
Constraints:
$-2^{31}$ <= val <= $2^{31}$ - 1
pop
, top
and getMin
operations will always be called on non-empty stacks.3 * $10^4$
calls will be made to push
, pop
, top
, and getMin
.주어진 문제는 push, pop, top과 최솟값을 검색하는 getMin 함수들을 모두 의 시간복잡도로 구현해야 합니다.
입출력, 조건 및 제약들을 살펴보겠습니다.
이 문제가 Medium난이도인것은 아무래도 최솟값을 바로바로 구해야 한다는 점에 있는것 같습니다. 또한 O(1)의 시간 복잡도로 구현해야 합니다. 이 뜻은 기본 스택에 값을 넣고 빼야 하지만, 최솟값만을 따로 저장하는 스택 자료구조 1개를 더 만들어야 한다는 것을 의미합니다.
왜냐하면 스택 자료구조에서 진행되는 함수들은 모두 O(1)의 시간 복잡도로 구현할 수 있습니다. 거기다 최솟값을 따로 저장할려면 최소값만을 담는 스택 자료구조를 따로 만든다면 해결할 수 있습니다.
그럼 이것을 기반으로 바로 코드 설계를 해보도록 하겠습니다.
self.stack
).self.min_stack
).min_stack
에는 현재 스택의 최솟값만을 저장하여 최솟값을 시간에 조회 가능하도록 한다.push
메서드:min_stack
이 비어 있거나, 새로운 값이 min_stack
의 최상단 값보다 작거나 같으면 min_stack
에도 추가.pop
메서드:min_stack
의 최상단 값과 동일하다면, min_stack
에서도 제거.top
메서드:getMin
메서드:min_stack
의 최상단 값을 반환하여 최솟값을 조회.class MinStack(object):
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, val):
"""
:type val: int
:rtype: None
"""
self.stack.append(val)
# 최솟값 스택 업데이트
if not self.min_stack or val <= self.min_stack[-1]:
self.min_stack.append(val)
def pop(self):
"""
:rtype: None
"""
if self.stack:
val = self.stack.pop()
if val == self.min_stack[-1]:
self.min_stack.pop()
def top(self):
"""
:rtype: int
"""
return self.stack[-1]
def getMin(self):
"""
:rtype: int
"""
return self.min_stack[-1]
push
: 새로운 값을 기본 스택에 추가하고, 필요하면 min_stack
에도 추가.pop
: 기본 스택에서 값을 제거하고, min_stack
에서도 최솟값이 제거되는 경우 처리.top
: 기본 스택의 최상단 값을 반환.getMin
: min_stack
의 최상단 값을 반환해 시간에 최솟값을 조회.push
: (값 추가 및 min_stack
업데이트)pop
: (값 제거 및 min_stack
업데이트)top
: (최상단 값 반환)getMin
: (최솟값 반환)간단한 스택 문제처럼 보였지만, 추가 스택을 활용해 각 연산을 최적화한 점이 매우 흥미로웠습니다. 이 과정에서 자료구조 설계의 유연성과 효율성을 다시 한번 느꼈습니다. 특히, 의 시간 복잡도를 유지하면서도 스택의 본래 특성을 활용한 점이 인상적이었습니다.
전체 코드는 다음 링크에서 확인할 수 있습니다.
읽어주셔서 감사합니다.