946. Validate Stack Sequences
Problem Description
You are given two integer arrays pushed and popped, where each array contains distinct values. These arrays represent a potential sequence of push and pop operations on a stack.
The pushed array represents the order in which elements were pushed onto a stack, and the popped array represents the order in which elements were popped from the stack.
Your task is to determine if the popped sequence is a valid result that could have been obtained by performing push and pop operations on an initially empty stack using the elements from pushed in the given order.
You need to return true if it's possible to achieve the popped sequence through valid stack operations, or false if it's impossible.
For example:
- If
pushed = [1, 2, 3, 4, 5]andpopped = [4, 5, 3, 2, 1], this is valid because:- Push 1, 2, 3, 4 → Pop 4
- Push 5 → Pop 5
- Pop 3, 2, 1
The key constraint is that you must push elements in the exact order given by pushed, but you can choose when to pop elements as long as you follow stack rules (last-in-first-out).
Intuition
To validate if a sequence of pops is possible, we need to simulate the actual stack operations. The key insight is that we must push elements in the exact order given by pushed, but we have flexibility in when we pop elements.
Think about how a stack works: when we push elements, they stack on top of each other. When we pop, we can only remove the top element. So at any point during the pushing process, we can check if the current top of the stack matches the next element we need to pop according to popped.
The strategy is straightforward:
- Push elements from
pushedone by one onto a stack - After each push, check if we can perform any pops that match the required order in
popped - Keep popping as long as the top of the stack matches the next required element in
popped
For example, if we need to pop 4 next (according to popped), we keep pushing elements until 4 is at the top of the stack. Once it's there, we pop it and move to the next element in popped.
The process naturally handles all valid sequences because:
- If an element needs to be popped early, it will be popped as soon as it reaches the top
- If an element needs to be popped later, it will wait in the stack until all elements above it are popped first
If we successfully pop all elements in the order specified by popped, then the sequence is valid. We can verify this by checking if our pointer tracking the position in popped has reached the end of that array.
Learn more about Stack patterns.
Solution Approach
We implement the solution using stack simulation with a greedy popping strategy. Here's how the algorithm works:
-
Initialize data structures:
- Create an empty stack
stkto simulate the stack operations - Use a pointer
i = 0to track the current position in thepoppedarray
- Create an empty stack
-
Process each element in
pushed:- For each element
xin thepushedarray:- Push
xonto the stack withstk.append(x) - After pushing, immediately check if we can perform any valid pops
- Push
- For each element
-
Greedy popping logic:
- While the stack is not empty AND the top element equals
popped[i]:- Pop the top element from the stack with
stk.pop() - Increment the pointer
ito move to the next element inpopped
- Pop the top element from the stack with
- This greedy approach ensures we pop elements as soon as they match the required order
- While the stack is not empty AND the top element equals
-
Validation:
- After processing all elements in
pushed, check ifi == len(popped) - If
iequals the length ofpopped, it means we successfully popped all elements in the required order, so returntrue - Otherwise, return
false
- After processing all elements in
The algorithm has a time complexity of O(n) where n is the length of the arrays, since each element is pushed and popped at most once. The space complexity is O(n) for the stack in the worst case when all elements are pushed before any pop occurs.
The key insight is that the greedy popping strategy is both necessary and sufficient - we must pop an element as soon as it appears at the top and matches the next required element in popped, otherwise we might miss the opportunity to pop it in the correct order later.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with pushed = [1, 2, 3, 4, 5] and popped = [4, 5, 3, 2, 1].
Initial State:
- Stack:
[] - Pointer
i = 0(pointing topopped[0] = 4)
Step 1: Push 1
- Stack:
[1] - Check if top (1) equals
popped[0](4)? No, so don't pop iremains 0
Step 2: Push 2
- Stack:
[1, 2] - Check if top (2) equals
popped[0](4)? No, so don't pop iremains 0
Step 3: Push 3
- Stack:
[1, 2, 3] - Check if top (3) equals
popped[0](4)? No, so don't pop iremains 0
Step 4: Push 4
- Stack:
[1, 2, 3, 4] - Check if top (4) equals
popped[0](4)? Yes! Pop 4 - Stack:
[1, 2, 3],i = 1(now pointing topopped[1] = 5) - Check if top (3) equals
popped[1](5)? No, stop popping
Step 5: Push 5
- Stack:
[1, 2, 3, 5] - Check if top (5) equals
popped[1](5)? Yes! Pop 5 - Stack:
[1, 2, 3],i = 2(now pointing topopped[2] = 3) - Check if top (3) equals
popped[2](3)? Yes! Pop 3 - Stack:
[1, 2],i = 3(now pointing topopped[3] = 2) - Check if top (2) equals
popped[3](2)? Yes! Pop 2 - Stack:
[1],i = 4(now pointing topopped[4] = 1) - Check if top (1) equals
popped[4](1)? Yes! Pop 1 - Stack:
[],i = 5
Final Check:
i = 5which equalslen(popped) = 5- Return
true- the sequence is valid!
The key observation is that after pushing 4, we immediately pop it because it matches what we need. Then after pushing 5, we enter a chain of pops (5→3→2→1) as each exposed top element matches the next required element in the popped sequence.
Solution Implementation
1class Solution:
2 def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
3 """
4 Validates if a given popped sequence could have been generated from the pushed sequence
5 using a stack.
6
7 Args:
8 pushed: List of integers representing the push sequence
9 popped: List of integers representing the pop sequence
10
11 Returns:
12 bool: True if the popped sequence is valid, False otherwise
13 """
14 # Initialize an empty stack to simulate the push/pop operations
15 stack = []
16
17 # Index to track the current position in the popped sequence
18 pop_index = 0
19
20 # Iterate through each element in the pushed sequence
21 for push_value in pushed:
22 # Push the current value onto the stack
23 stack.append(push_value)
24
25 # Try to pop elements that match the expected pop sequence
26 # Continue popping while the stack top matches the current element in popped
27 while stack and stack[-1] == popped[pop_index]:
28 stack.pop()
29 pop_index += 1
30
31 # If all elements in popped have been matched, the sequence is valid
32 return pop_index == len(popped)
331class Solution {
2 public boolean validateStackSequences(int[] pushed, int[] popped) {
3 // Use a stack to simulate the push and pop operations
4 Deque<Integer> stack = new ArrayDeque<>();
5
6 // Index to track the current position in the popped array
7 int popIndex = 0;
8
9 // Iterate through each element in the pushed array
10 for (int pushedValue : pushed) {
11 // Push the current element onto the stack
12 stack.push(pushedValue);
13
14 // Try to pop elements from the stack if they match the expected pop sequence
15 // Continue popping while:
16 // 1. The stack is not empty
17 // 2. The top of the stack matches the current element in popped array
18 while (!stack.isEmpty() && stack.peek() == popped[popIndex]) {
19 stack.pop();
20 popIndex++;
21 }
22 }
23
24 // If all elements in popped array have been matched, the sequences are valid
25 return popIndex == popped.length;
26 }
27}
281class Solution {
2public:
3 bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
4 // Use a stack to simulate the push and pop operations
5 stack<int> simulationStack;
6
7 // Index to track the current position in the popped sequence
8 int popIndex = 0;
9
10 // Iterate through each element in the pushed sequence
11 for (int currentElement : pushed) {
12 // Push the current element onto the stack
13 simulationStack.push(currentElement);
14
15 // Try to pop elements that match the expected pop sequence
16 // Continue popping while:
17 // 1. The stack is not empty
18 // 2. The top element matches the current expected pop element
19 while (!simulationStack.empty() && simulationStack.top() == popped[popIndex]) {
20 simulationStack.pop();
21 popIndex++;
22 }
23 }
24
25 // If all elements in popped sequence were matched, popIndex should equal popped.size()
26 return popIndex == popped.size();
27 }
28};
291/**
2 * Validates if a given popped sequence could be the result of push and pop operations
3 * on an initially empty stack, given the pushed sequence.
4 *
5 * @param pushed - Array representing the order in which elements are pushed to the stack
6 * @param popped - Array representing the order in which elements should be popped from the stack
7 * @returns true if the popped sequence is valid, false otherwise
8 */
9function validateStackSequences(pushed: number[], popped: number[]): boolean {
10 // Initialize an empty stack to simulate push/pop operations
11 const stack: number[] = [];
12
13 // Index to track the current position in the popped array
14 let popIndex = 0;
15
16 // Iterate through each element in the pushed array
17 for (const element of pushed) {
18 // Push the current element onto the stack
19 stack.push(element);
20
21 // Try to pop elements from the stack if they match the expected pop sequence
22 while (stack.length > 0 && stack[stack.length - 1] === popped[popIndex]) {
23 // Remove the top element from the stack
24 stack.pop();
25 // Move to the next element in the popped sequence
26 popIndex++;
27 }
28 }
29
30 // If all elements in popped array were matched, the sequence is valid
31 return popIndex === popped.length;
32}
33Time and Space Complexity
Time Complexity: O(n), where n is the length of the pushed array.
The algorithm iterates through each element in the pushed array exactly once using the outer for loop. Although there's a while loop inside, each element can only be pushed onto the stack once and popped from the stack once. Therefore, the total number of operations across the entire execution is at most 2n (each element is pushed once and popped at most once), which simplifies to O(n).
Space Complexity: O(n), where n is the length of the pushed array.
The space complexity is determined by the auxiliary stack stk used in the algorithm. In the worst-case scenario, all elements from the pushed array could be on the stack simultaneously before any popping occurs. This happens when the popped sequence requires all elements to be pushed first before any can be popped (for example, when popped is the reverse of pushed). Therefore, the maximum space required is O(n).
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Forgetting to Check Stack Non-Empty Condition
A critical pitfall is accessing stack[-1] without first verifying the stack is non-empty. While the provided solution correctly includes stack and in the while condition, developers often forget this check when implementing the solution from scratch.
Incorrect Implementation:
# WRONG - May cause IndexError while stack[-1] == popped[pop_index]: stack.pop() pop_index += 1
Correct Implementation:
# CORRECT - Checks stack is non-empty first while stack and stack[-1] == popped[pop_index]: stack.pop() pop_index += 1
2. Index Out of Bounds for popped Array
Another common mistake is not checking if pop_index is within bounds before accessing popped[pop_index]. This can cause an IndexError when all elements have been successfully popped.
Incorrect Implementation:
# WRONG - May access popped[pop_index] when pop_index == len(popped) while stack and stack[-1] == popped[pop_index]: stack.pop() pop_index += 1
Correct Implementation:
# CORRECT - Add boundary check for pop_index
while stack and pop_index < len(popped) and stack[-1] == popped[pop_index]:
stack.pop()
pop_index += 1
3. Using Wrong Validation Logic
Some developers mistakenly check if the stack is empty instead of checking if all elements in popped have been processed.
Incorrect Implementation:
# WRONG - Stack being empty doesn't guarantee all pops were successful
return len(stack) == 0
Correct Implementation:
# CORRECT - Verifies all elements in popped were matched
return pop_index == len(popped)
4. Not Understanding the Greedy Nature is Mandatory
A conceptual pitfall is thinking we have flexibility in when to pop elements. The greedy approach (popping immediately when possible) is not just an optimization—it's mandatory for correctness. Delaying a pop when it's possible will make it impossible to achieve certain valid sequences.
Example demonstrating why greedy is necessary:
pushed = [1, 2],popped = [2, 1]- If we don't pop 2 immediately after pushing it, we'd have stack
[1, 2]after all pushes - We'd then be forced to pop in order
[2, 1], which matches our target - But consider
pushed = [1, 2, 3],popped = [2, 3, 1] - If we don't pop 2 after pushing it, we get stack
[1, 2, 3] - Now we can't achieve the required pop order since 3 must come before 2
What is the best way of checking if an element exists in a sorted array once in terms of time complexity? Select the best that applies.
Recommended Readings
Stack Intro New to stacks This article provides a quick review For a comprehensive beginner friendly lesson on stacks check out our Foundation Course Stack module courses foundation stack_lifo_model Imagine you have a pile of books on your desk If you want to add a new book you place it on top
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Want a Structured Path to Master System Design Too? Don’t Miss This!