Zero To DSAZero To DSA
Privacy Policy
Learning Path
Big O & ComplexityArrays & StringsHashMaps & SetsLinked ListsStacks & QueuesRecursion & BacktrackingSorting & SearchingGreedy & IntervalsTrees & TriesGraphsDynamic Programming

Stacks & Queues

intermediate5 problems· Prerequisites: Big O & Complexity, Arrays & Strings, Linked Lists
Learn
Practice
Exam

Stack (LIFO)

A stack follows Last In, First Out. Think of a stack of plates — you add and remove from the top.

OperationStack
PushO(1)
PopO(1)
PeekO(1)

Uses: Undo/redo, backtracking, expression evaluation, DFS (implicitly via recursion).

Stack usageC#
var stack = new Stack<int>();

stack.Push(1);  // [1]
stack.Push(2);  // [1, 2]
stack.Push(3);  // [1, 2, 3]

int top = stack.Peek();  // 3 (no removal)
int popped = stack.Pop(); // 3, stack is now [1, 2]

// Monotonic stack pattern — maintain increasing/decreasing order
int[] NextGreaterElement(int[] arr) {
    var result = new int[arr.Length];
    Array.Fill(result, -1);
    var monoStack = new Stack<int>(); // stores indices

    for (int i = 0; i < arr.Length; i++) {
        while (monoStack.Count > 0 && arr[i] > arr[monoStack.Peek()]) {
            int idx = monoStack.Pop();
            result[idx] = arr[i];
        }
        monoStack.Push(i);
    }
    return result;
}
// For [2, 1, 3], returns [3, 3, -1]

Queue (FIFO)

A queue follows First In, First Out. Think of a line at a store.

OperationQueue
EnqueueO(1)
DequeueO(1)
PeekO(1)

Uses: BFS, task scheduling, buffering, sliding window.

Queue usageC#
var queue = new Queue<int>();

queue.Enqueue(1);  // [1]
queue.Enqueue(2);  // [1, 2]
queue.Enqueue(3);  // [1, 2, 3]

int front = queue.Peek();  // 1 (no removal)
int dequeued = queue.Dequeue(); // 1, queue is now [2, 3]

// BFS template using Queue
void Bfs(TreeNode root) {
    var q = new Queue<TreeNode>();
    q.Enqueue(root);

    while (q.Count > 0) {
        int levelSize = q.Count;
        for (int i = 0; i < levelSize; i++) {
            var node = q.Dequeue();
            Console.Write(node.val + " ");
            if (node.left != null) q.Enqueue(node.left);
            if (node.right != null) q.Enqueue(node.right);
        }
        Console.WriteLine(); // new level
    }
}

Priority Queue

A priority queue dequeues elements by priority, not insertion order.

OperationPriority Queue
EnqueueO(log n)
DequeueO(log n)
PeekO(1)

Uses: Dijkstra's algorithm, Huffman coding, K smallest/largest elements.

PriorityQueue usageC#
// Min-heap by default (lower priority = dequeued first)
var pq = new PriorityQueue<string, int>();

pq.Enqueue("low", 3);
pq.Enqueue("high", 1);
pq.Enqueue("medium", 2);

string next = pq.Dequeue(); // "high" (priority 1)

// For max-heap, negate priorities or use a custom comparer
var maxHeap = new PriorityQueue<int, int>(
    Comparer<int>.Create((a, b) => b.CompareTo(a))
);

// Top K frequent elements pattern
int[] TopKFrequent(int[] nums, int k) {
    var counts = new Dictionary<int, int>();
    foreach (var n in nums) counts[n] = counts.GetValueOrDefault(n) + 1;

    var heap = new PriorityQueue<int, int>();
    foreach (var kvp in counts) {
        heap.Enqueue(kvp.Key, kvp.Value);
        if (heap.Count > k) heap.Dequeue(); // keep only top K
    }

    var result = new int[k];
    for (int i = 0; i < k; i++) result[i] = heap.Dequeue();
    return result;
}

Common Interview Patterns

  1. Monotonic stack — next greater element, daily temperatures, largest rectangle in histogram
  2. Valid parentheses — classic stack problem with matching brackets
  3. Queue with two stacks — implement a queue using two stacks
  4. Min stack — stack that supports GetMin() in O(1)
  5. Level-order traversal — BFS using a queue (tree problems)
  6. Top K elements — use PriorityQueue to efficiently track K largest/smallest