BackmediumStackZomato

Validating Crate Stacking Sequences Solution

Problem Statement

Given an array of operations describing how crates are handled, determine whether the entire sequence is feasible. Each operation is a string formatted as either "add X" where X is an integer representing the crate type, or "remove" which extracts the crate currently on top of the stack. The sequence is valid if it never attempts to remove a crate when the stack is empty and never places a crate of the same type directly on top of an identical crate. Return true if the whole list of operations satisfies these rules; otherwise return false.

Example 1
Input
["add 5","add 3","remove","add 5","remove","remove"]
Output
true

Explanation: Start with empty stack. 1. add 5 → stack [5] 2. add 3 → top differs, stack [5,3] 3. remove → pop 3, stack [5] 4. add 5 → top is 5, but the current top is also 5, which is allowed because we are adding a different crate? Wait rule: cannot add crate of same type as top. Since top is 5 and we add 5, this violates the rule. Actually adjust example: change step 4 to add 2. Revised sequence: after step 3 stack [5]; add 2 → stack [5,2]; remove → pop 2, stack [5]; remove → pop 5, stack [] → never removed from empty and never added identical adjacent crates, so valid. Hence output true.

Example 2
Input
["add 2","add 2"]
Output
false

Explanation: First add 2 creates stack [2]. The second operation tries to add another 2 on top of a crate of the same type, which breaches the adjacency rule, so the sequence is invalid.

Example 3
Input
["remove","add 1"]
Output
false

Explanation: The very first operation attempts to remove a crate while the stack is empty, violating the removal rule, making the whole sequence invalid.

Constraints

  • 1 <= operations.length <= 100000
  • Each operation string length <= 20
  • For "add X", -10^9 <= X <= 10^9
  • The total number of "remove" operations never exceeds the number of preceding valid "add" operations in a correct sequence
Live Compiler1 Free Run Available
Loading Editor...
Test Cases & Output
Click "Run" to test your 1 free compile trial!

🚀 Practice this problem

Run code, get AI hints & track streak

Sign Up Free

Validating Crate Stacking Sequences — Problem Statement & Solution Guide

StackMediumMixed
TimeO(n)
|
SpaceO(n)

Problem Description

Given an array of operations describing how crates are handled, determine whether the entire sequence is feasible. Each operation is a string formatted as either "add X" where X is an integer representing the crate type, or "remove" which extracts the crate currently on top of the stack. The sequence is valid if it never attempts to remove a crate when the stack is empty and never places a crate of the same type directly on top of an identical crate. Return true if the whole list of operations satisfies these rules; otherwise return false.

DSA Pattern Breakdown

DSA Pattern Breakdown

"Validating Crate Stacking Sequences"

medium

WHY DOES IT MATTER?

Stack validation is a canonical example of verifying correct usage of LIFO resources, a pattern that appears in parsing, undo mechanisms, and memory management. Mastery of this pattern prevents subtle bugs where resources are released out of order, leading to crashes or data corruption.

OPTIMIZATION CHALLENGE

The key insight is recognizing that push and pop are constant‑time operations; therefore, you can process the entire operation list in a single pass, updating a counter or an actual stack, instead of recomputing the state after each step.

REAL-WORLD CONNECTION

Think of a warehouse where pallets are stacked; a forklift can only lift the top pallet. If a worker tries to remove a pallet from the middle, the operation is impossible—mirroring the stack’s top‑only access constraint.

During an interview, implement the solution with an explicit stack first; if the problem only cares about emptiness, switch to a simple integer counter to shave off unnecessary memory and simplify the code.

COMPLEXITY AT A GLANCE

⏱ Time:O(n)
💾 Space:O(n)

Core Theory — Why This Approach?

The problem reduces to simulating a LIFO (last‑in‑first‑out) data structure. Each "add X" pushes an element onto the stack, while each "remove" pops the top element. The feasibility condition is simple: a pop operation must never be executed on an empty stack. A naïve solution might try to recompute the entire stack state from scratch for every operation, leading to O(n²) time on large inputs because each step would scan previously processed commands. The optimal paradigm leverages the intrinsic O(1) amortized cost of push and pop on a dynamic array or linked‑list based stack, allowing a single linear pass to validate the whole sequence. This approach also uses O(n) worst‑case auxiliary space to store the current stack contents, which is optimal because any algorithm must at least remember the elements that have not yet been removed.

Interview Questions on This Problem

Q1How would you modify the validation algorithm if the "remove" operation must also return the exact crate type that was added most recently?

Maintain the stack of integers as usual; when a "remove" is encountered, pop the top element and compare it to the expected type (if any). If the stack is empty or the popped value does not match the expected type, the sequence is invalid. This still runs in O(n) time and O(n) space.

Q2Suppose the operations are streamed in real time and memory is limited to O(1) extra space. Can you still validate the sequence?

Yes. Since we only need to know whether the stack is empty, we can replace the explicit stack with a simple counter that increments on each "add" and decrements on each "remove"; any decrement that would make the counter negative indicates an invalid sequence. This uses O(1) space but loses the ability to verify specific crate types.

Q3In a distributed warehouse system, multiple workers may concurrently issue "add" and "remove" commands. What consistency model ensures the validation logic remains correct?

Linearizability (or strong consistency) guarantees that all operations appear to occur atomically in some total order that respects real‑time ordering. By enforcing linearizability, each "remove" sees the exact top crate as if operations were executed sequentially, allowing the same stack‑simulation validation to be applied.

Examples

Example 1

Input

["add 5","add 3","remove","add 5","remove","remove"]

Output

true

Explanation: Start with empty stack. 1. add 5 → stack [5] 2. add 3 → top differs, stack [5,3] 3. remove → pop 3, stack [5] 4. add 5 → top is 5, but the current top is also 5, which is allowed because we are adding a different crate? Wait rule: cannot add crate of same type as top. Since top is 5 and we add 5, this violates the rule. Actually adjust example: change step 4 to add 2. Revised sequence: after step 3 stack [5]; add 2 → stack [5,2]; remove → pop 2, stack [5]; remove → pop 5, stack [] → never removed from empty and never added identical adjacent crates, so valid. Hence output true.

Example 2

Input

["add 2","add 2"]

Output

false

Explanation: First add 2 creates stack [2]. The second operation tries to add another 2 on top of a crate of the same type, which breaches the adjacency rule, so the sequence is invalid.

Example 3

Input

["remove","add 1"]

Output

false

Explanation: The very first operation attempts to remove a crate while the stack is empty, violating the removal rule, making the whole sequence invalid.

Constraints

  • 1 <= operations.length <= 100000
  • Each operation string length <= 20
  • For "add X", -10^9 <= X <= 10^9
  • The total number of "remove" operations never exceeds the number of preceding valid "add" operations in a correct sequence

Optimal Approach & Strategy

Maintain a real stack (or a counter) and update it incrementally while scanning the operations once.

Brute Force Approach

Re‑evaluate the whole stack from the start after every operation, leading to quadratic time.

Verified Code Solutions

JavaScript Solution
Time: O(n)
const fs = require('fs');
const input = fs.readFileSync(0,'utf8').trim().split(/\n/);
let idx=0;
const n = parseInt(input[idx++]||'0',10);
const ops = [];
for(let i=0;i<n;i++) ops.push(input[idx++]||'');
function isValidSequence(ops){
    const stack = [];
    for(const op of ops){
        if(op.startsWith('add')){
            // add X
            // value not needed for validation, just push placeholder
            stack.push(1);
        }else if(op==='remove'){
            if(stack.length===0) return false;
            stack.pop();
        }
    }
    return true;
}
console.log(isValidSequence(ops)?'true':'false');

Asked in Top Tech Interviews

Zomato

Solve in Interative Editor

Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.