Beginner: foundations · Stacks, queues and linked lists · topic 16 of 61 · 35 min
Stacks
Explanation
Last in, first out
A stack is a collection where you add and remove items at the same end, called the top. The last item pushed is the first one popped: last in, first out, or LIFO. You cannot reach an item in the middle without first removing everything above it.
Operations and their cost
| Operation | Python list | Cost |
|---|---|---|
| push x | stack.append(x) | O(1) amortised |
| pop (remove and return the top) | stack.pop() | O(1) |
| peek (look at the top) | stack[-1] | O(1) |
| is it empty? | not stack | O(1) |
| size | len(stack) | O(1) |
A Python list works as a stack because append and pop work at the end, where nothing has to shift. pop() on an empty list raises IndexError: pop from empty list, and stack[-1] on an empty list raises IndexError too, so check if stack: first. In JavaScript use an array with push and pop, and arr[arr.length - 1] to peek.
Every running program also has a stack: the call stack remembers which function called which, and each recursive call pushes a new frame. You will lean on that in Module 5.
Valid brackets
A string of brackets is valid when every opening bracket is closed by the same kind of bracket, in the right order: "([]{})" is valid, "([)]" is not. The most recent unclosed bracket must be closed first, which is exactly LIFO. Push every opening bracket. On a closing bracket, the top of the stack must be its partner, so pop and compare. At the end the stack must be empty, or some bracket was never closed. O(n) time, and O(n) space in the worst case, such as "((((".
def is_valid(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for c in s:
if c in "([{":
stack.append(c)
elif c in pairs:
if not stack or stack.pop() != pairs[c]:
return False
return not stack
print(is_valid("{[()]}"), is_valid("([)]"), is_valid("((")) # Output: True False FalsePostfix (Reverse Polish) expressions
We usually write 3 + 4 × 2 with the operator between the numbers (infix), which needs precedence rules and brackets. In postfix, also called Reverse Polish Notation (RPN), each operator comes after its two operands: "3 4 2 * +" means 3 + (4 × 2) = 11. No brackets or precedence rules are needed, and a stack evaluates it in one pass: push numbers; on an operator, pop two numbers, apply the operator, and push the result.
| Token | Action | Stack after |
|---|---|---|
| 3 | push | [3] |
| 4 | push | [3, 4] |
| 2 | push | [3, 4, 2] |
| * | pop 2 and 4, push 4 × 2 | [3, 8] |
| + | pop 8 and 3, push 3 + 8 | [11] |
Order matters for − and ÷: the FIRST pop is the right operand. For "8 3 -", pop 3 (call it b), then 8 (a), and compute a − b = 5, not 3 − 8.
Division that truncates toward zero
Many problems say integer division "truncates toward zero", as in C, C++ and Java: 7 ÷ 2 = 3 and −7 ÷ 2 = −3. Python's // rounds DOWN (toward minus infinity), so −7 // 2 is −4. int(a / b) truncates, but it goes through a float, which can lose precision for very large numbers. A safe integer way is to divide the absolute values and put the sign back.
print(-7 // 2) # Output: -4 (floor: rounds down)
print(int(-7 / 2)) # Output: -3 (toward zero, via a float)
def div_trunc(a, b):
q = abs(a) // abs(b)
return -q if (a < 0) != (b < 0) else q
print(div_trunc(-7, 2), div_trunc(7, -2), div_trunc(-7, -2)) # Output: -3 -3 3Min-stack: the minimum in O(1)
A min-stack supports push, pop, top and get_min, all in O(1). Calling min(stack) would be O(n). The trick: store next to each value the minimum of the stack at the moment it was pushed. The top pair always knows the current minimum, and popping brings back the older minimum automatically. It costs O(n) extra space.
stack = [] # pairs (value, minimum so far)
for x in [5, 3, 7, 3]:
low = min(x, stack[-1][1]) if stack else x
stack.append((x, low))
print(stack) # Output: [(5, 5), (3, 3), (7, 3), (3, 3)]
stack.pop()
stack.pop()
print(stack[-1][1]) # Output: 3
stack.pop()
print(stack[-1][1]) # Output: 5Common mistakes
- Popping or peeking an empty stack (IndexError). Fix: check if stack: first and decide what to return.
- In the bracket check, forgetting the final "is the stack empty?" test, so "((" passes. Fix: return not stack.
- Swapping operands in RPN and computing b − a. Fix: the first pop is the RIGHT operand.
- Using // when the task says "truncate toward zero". Fix: divide absolute values and fix the sign.
- Using insert(0, x) and pop(0) as the stack top: both are O(n). Fix: push and pop at the end.
- A min-stack that calls min() on every get_min. Fix: store the running minimum with each item.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Stacks · 1/8
This lesson is about stacks: last in, first out.
Prefer a video by a teacher? Find free videos on “stack data structure valid parentheses evaluate reverse polish notation min stack” on YouTube ↗
In real life: Undo in a text editor
Editors such as the ones used for writing code or documents keep every change on an undo stack. Ctrl+Z pops the latest change and pushes it onto a redo stack; Ctrl+Y pops from the redo stack and pushes it back. Typing something new clears the redo stack, because the old future no longer applies. Real editors group keystrokes into larger changes, but the two-stack idea is the same.
undo, redo = [], []
text = ""
for word in ["Namaste", " from", " Pune"]:
undo.append(text) # remember the state before each change
text += word
redo.clear()
print(text)
redo.append(text)
text = undo.pop() # Ctrl+Z
print(text)
undo.append(text)
text = redo.pop() # Ctrl+Y
print(text)Practice (0/3 done)
Write is_valid_brackets(s) that returns True if every bracket in s is closed by the same kind of bracket in the right order. The brackets are ( ) [ ] { }; every other character (letters, digits, spaces) is ignored. Use a stack: O(n) time. Example: is_valid_brackets("a(b[c]d)e") returns True and is_valid_brackets("([)]") returns False.
Write eval_rpn(tokens) that evaluates a postfix (Reverse Polish) expression given as a list of strings. Numbers are integers (they can be negative, like "-11"); the operators are "+", "-", "*" and "/". Division between integers TRUNCATES TOWARD ZERO (7 / -2 is -3, not -4), and there is never a division by zero. The expression is always valid. Example: eval_rpn(["2", "1", "+", "3", "*"]) returns 9.
Complete the class MinStack with push(x), pop(), top() and get_min(), each in O(1) time. pop() removes the top item and returns it; top() returns the top item without removing it; get_min() returns the smallest item in the stack. On an empty stack, pop(), top() and get_min() return None. Values can repeat and can be negative.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Queues and dequesStacks, queues and linked lists · same module
- Monotonic stacks and queuesStacks, queues and linked lists · same module
- Linked listsStacks, queues and linked lists · same module
- StacksC Programming (from zero to systems) · Data structures in C
- Stacks and queuesPython Programming · Algorithms, data structures and testing
- Queues, stacks and priority queuesJava Programming (Core to Spring Boot) · The collections framework
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
You push 1, 2 and 3, pop once, then push 4. What does peek return now?
Answer: 4
Popping removes 3; then 4 goes on top of 2.
Which Python list operations make a stack with O(1) push and pop?
Answer: append and pop()
Working at the end needs no shifting. Anything at index 0 shifts the whole list, O(n).
What is the value of the postfix expression "6 2 / 3 -"?
Answer: 0
6 / 2 = 3, then 3 − 3 = 0.
With division that truncates toward zero, what is −9 ÷ 4?
Answer: −2
−2.25 truncated toward zero is −2. Python's −9 // 4 would give −3.
How does a min-stack answer get_min in O(1)?
Answer: Each entry stores the minimum of the stack at the moment it was pushed
The top entry already knows the current minimum, and popping reveals the older one.
What is the time complexity of push and pop?Related
s = []; s.append(1); s.append(2); s.append(3); s.pop(); What does s.pop() return now?Related
Which order does a stack follow?Related
What does Navigator.pop(context) do?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 4 more topics in “Stacks, queues and linked lists” before its exam: Queues and deques, Monotonic stacks and queues, Linked lists, Fast and slow pointers and merging lists.
- Module 4 exam: Stacks, queues and linked lists · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Recursion and backtracking. 61 topics left in the course before the final exam.