shelvesStack, Queue, Heap

Notes and typical questions for Stack, Queue or Heap related problems

Notes

  • When performing stack-like operations on a String, using a StringBuilder is often simpler and more efficient than using an explicit stack data structure.

  • Although sliding windows questions are usually related to the 2-pointer solution. If the sliding windows question needs to compare numbers within the window, you also need to consider the solution: 2-pointer + monotonic queue.

  • PruorityQueue

    • poll(): Remove the head item

  • In Java, ArrayDeque is faster than LinkedList except for removing elements. Reference:https://stackoverflow.com/questions/6163166/why-is-arraydeque-better-than-linkedlistarrow-up-right

Typical Questions (37)

Mutual implementation between Queue and Stack (2)

  • LC 232. Implement Queue using Stacks

    • # Analysis on amortized O(1) TC for pop
      # Assumption: When stack2 is empty, get pop calls for all items in the queue
      first pop:   O(2*n) transfer + O(1) pop
      other pops:  (n - 1) * O(1)  → O(n - 1)
      -------------------------------
      Total operations overall n pop calls: 2*n+1+n-1 = 3*n
      Amortized TC for pop: (3*n)/n ≈ O(1)
  • 🟠 LC 225. Implement Stack using Queues

    • Approach 1: Use 1 queue. Straightforward

    • Approach 2: Use 2 queues

      • 2.1 Push O(n)O(n), Pop O(1)O(1): NOT straightforward, queue1 is to store all elements in stack order with the help of queue2

      • 2.2 Push O(1)O(1), Pop O(n)O(n). Not preferred compared to 2.1.

Normal Stack Common Use Cases (8)

  • Notes

    • Common cases

      • Matching / Pairing: resolve parentheses or symbols

      • Adjacent Merge / Reduction: repeatedly merge/remove neighbors based on a rule

      • Expression Evaluation: operators, precedence, calculators

      • Nested Structure Parsing: decode nested patterns

      • State Backtracking: undo previous state (path/string)

  • LC 20. Valid Parentheses

    • The most elegant way is to push ) or ] or ] when get ( or [ or {. This way can simplify if/else logic

    • Optimal Answerarrow-up-right. TC: O(n)O(n), SC: O(n)O(n)

  • LC 1047. Remove All Adjacent Duplicates In String

    • Approach 1: Use a stack, the most straightforward way

    • 👍 Approach 2: Use 2 pointers, this way is better due to no space usage for the stack

  • LC 1209. Remove All Adjacent Duplicates in String II

  • LC 150. Evaluate Reverse Polish Notation

  • LC 71. Simplify Path

  • LC 2390. Removing Stars From a String

    • Stack approach: Use StringBuilder to simulate Stack. Answerarrow-up-right. TC: O(n)O(n), SC: O(n)O(n)

    • 2 pointers approach: Answerarrow-up-right.

      • TC: O(n)O(n)

      • SC: pseudoO(1)pseudo-O(1) due to the immutability of String in Java

  • LC 735. Asteroid Collision

  • 🌟 🔴 LC 394. Decode String

    • It's very hard to implement. I check the solution directly. Go through this test case "3[a2[c]2[d]]" to understand why the solution works...

    • Optimal Answerarrow-up-right.

      • TC: O(max(k)n)O(max(k)*n), where max(k)max(k) is the max value of k, n is the size of the string array.

      • SC: O(n)O(n).

  • 🟠 LC 224. Basic Calculator

    • It's similar to the above LC 394 question.

    • Hints

      • Try to resolve it using 1 stack.

        • Store signs ('+', '-') using an int var instead of a stack.

      • Try to handle numbers in the input string that have more than 1 digit without using a while loop

    • I finally made it by myself (I already saw the solution in previous rounds)!

    • Optimal Answer.arrow-up-right TC: O(nO(n), SC: O(n)O(n)

  • 🟠 LC 227. Basic Calculator II

    • Although it does not have () , but it's more complicated than LC 224 due to */

    • Optimal Answerarrow-up-right. TC: O(n)O(n), SC: O(1)O(1)

  • 🟠 LC 1249. Minimum Remove to Make Valid Parentheses

    • Approach 1

      • I came up with this approach independently before checking the LeetCode editorial. The core idea is similar to the solution for LC 224 (Basic Calculator).

      • Answerarrow-up-right. TC: O(n2)O(n^2), SC: O(n)O(n).

        • For TC, it's slow due to repeated string copying when merging nested builders. Conceptually, the process resembles: b1.append(b2.append(...append(bk)...)); where deeply nested parentheses cause the same characters to be copied multiple times.

    • 👍 Approach 2: Optimal Answerarrow-up-right. TC: O(nO(n), SC: O(n)O(n)

  • LC 2197. Replace Non-Coprime Numbers in Array

Normal Queue Common Use Cases (3)

  • LC 933. Number of Recent Calls

  • LC 649. Dota2 Senate

  • LC 346. Moving Average from Data Stream

  • LC 362. Design Hit Counter

    • At first, I used binary search in getHits() and didn't remove anything in the queue because I didn't realize that getHits() is called with timestamps in increasing order as well.

    • Optimal Answer.

      • TC: Both hit() and getHits(): amortized O(1)O(1)

      • SC: O(1). Max 300 items in the queue.

Monotonic Queue (1)

Monotonic Stack (11)

  • Use case: For an element in an array, when you need to find the index/value of the 1st element to the left/right that is greater/smaller than it.

    • Basic requirements for 1st Element:

      • Example: Find the next greater element in elements after the current element.

      • Use a monotonic stack to maintain indices in an increasing or decreasing order (order is determined by the value of indexes) based on the requirement.

    • Complex requirements for 1st Element:

      • Example: Find the smallest element larger than the current element in the elements after it.

      • Steps

        • Create another array storing the index of the original array and preprocessing it by sorting indices based on values of the original array and secondary by indices to ensure order.

        • Traverse sorted indices and use a stack to handle the 1st element condition.

Basic Monotonic Stack Problems

  • 🌟 LC 739. Daily Temperatures

  • LC 496. Next Greater Element I

  • 🟠 LC 503. Next Greater Element II

    • Solve the circular problem by iterating the array twice.

    • In round 3, I somehow tried to use the remaining items in the stack to solve the circular problem, but that's NOT the correct way.

    • Optimal Answer. TC: O(n)O(n), SC: O(n)O(n)

  • 🟠 LC 901. Online Stock Span

  • LC 155. Min Stack

    • You can do the implementation with the Stack data structure.

    • Try to do it using only 1 stack.

    • Optimal Answerarrow-up-right. TC: O(1)O(1) for each operation. SC: O(n)O(n)

Trapping Rain Water Problems

  • 🌟 LC 42. Trapping Rain Water

    • Approach 1 with a stack

      • Accumulate the result by calculating the trapped water horizontally

      • When height[i] == stack.peekLast(), there are two valid approaches:

        1. Allow duplicate items in the stack: Push the current height[i] into the stack as usual.

        2. Keep only unique items in the stack: First, remove the older duplicate from the stack. Then, push the new height[i] into the stack. Reason: The new item can serve as the left boundary for the next rectangle, whereas the older duplicate is no longer useful.

      • Optimal Solutionarrow-up-right. TC: O(n)O(n), SC: O(n)O(n)

    • 🟠 Approach 2 with 2 pointers

Largest Rectangle Problem

  • 🌟 🔴 LC 84. Largest Rectangle in Histogram

    • It's a reversed version of LC 42.

    • It's easy to make mistakes when getting the width of the rectangle.

    • Optimal Answerarrow-up-right. TC: O(n)O(n), SC: O(n)O(n)

  • 🔴 LC 85. Maximal Rectangle

Advanced Monotonic Stack Problems

  • 🌟 🔴 LC 962. Maximum Width Ramp

    • This problem can also be resolved by 2 pointers + rightMax array (see that section). It's necessary to grasp this approach as well.

    • The monotonic stack is used for storing starting points. Need another array iteration from the end of the array to check valid results

    • Optimal Solutionarrow-up-right. TC: O(n)O(n), SC: O(n)O(n)

  • 🌟 🔴 LC 2863. Maximum Length of Semi-Decreasing Subarrays

    • This question is the same as LC 962

    • Approach 1: Monotonix Stack. TC: O(n)O(n), SC: O(n)O(n)

    • Approach 2: 2 pointers + rightMin array. TC: O(n)O(n), SC: O(n)O(n)

  • 🔴 LC 975. Odd Even Jump

    • This solution is based on DP + Monotonic Stack and this question can also be solved by DP + TreeMap

    • Optimal Solutionarrow-up-right. TC: O(nlogn)O(n*log{n}), SC: O(n)O(n)

Monotonic Deque (1)

  • 🔴 LC 3420. Count Non-Decreasing Subarrays After K Operations

    • This question is super hard and even the solution is very hard to understand. Add some comments in the optimal answer and go through some examples to get the idea.

      • I'm still not sure why reversing the array is more efficient.

    • Optimal Answerarrow-up-right. TC: O(n)O(n), SC: O(n)O(n)

Max/Min Heap Common Use Cases (11)

  • Notes

    • Whenever you see that you need to choose the k smallest or the k largest among a group of numbers always consider using a heap(priority queue).

  • 🌟 LC 347. Top K Frequent Elements

    • Learn how to initialize PriorityQueue with a custom Comparator

    • MinHeap Answerarrow-up-right: TC O(nlogk)O(n*log{k}), SC: O(n+k)O(n+k)

  • 🌟 LC 215. Kth Largest Element in an Array

  • 🟠 LC 2336. Smallest Number in Infinite Set

    • Optimal Answerarrow-up-right.

      • nn is the number addBack(num) and mm is the number of popSmallest() method calls.

      • TC: O((m+n)logn)O((m+n)*logn)

      • SC: O(n)O(n)

  • 🔴 LC 2542. Maximum Subsequence Score

    • Idea

      • k-1 largest numbers of nums2 will never be selected. For the selected number from nums2 in each possible score combination, it can only be the kth largest number or all other numbers which < kth largest number in nums2

      • For each possible score combination, the questions have 2 requirements (1 for nums1, 1 for nums2). It's impossible to consider both 2 requirements at the same time. Therefore, we need to fix 1 requirement first and sort out another requirement at the same time. Since we know the specific enumeration of the selected numbers in nums2, we can first fix the chosen numbers from nums2. Then, we can dynamically select the numbers from nums1 using a minHeap.

    • Optimal Answerarrow-up-right. TC: O(nlogn)O(n * log{n}). SC: O(n)O(n)

  • 🟠 LC 2462. Total Cost to Hire K Workers

    • Very easy to make mistakes during implementation.

    • Optimal Answerarrow-up-right

      • For the sake of brevity, let m be the given integer candidates

      • TC: O((k+m)logm)O((k+m)*log{m})

      • SC: O(m)O(m)

  • 🌟 🟠 LC 253. Meeting Rooms II

  • 🟠 LC 2402. Meeting Rooms III

    • Optimal Answerarrow-up-right

      • TC: O(MlogM+MlogN)O(M*logM + M*logN)

        • For inner while loop, It will have a maximum of N iterations each time, but it can't have N iterations every time. We can't pop more items than we have previously pushed, and we only push one 1 item per outer loop. Since we only push M times, we can only pop M-1 times over the whole function duration.

      • SC: O(N)O(N)

  • LC 3318. Find X-Sum of All K-Long Subarrays I

    • The idea is straightforward and just implementation is kind of long...

    • Optimal Answerarrow-up-right

      • TC: O(nklogx)O(n*k*log{x})

      • SC: O(k+x)O(k+x)

  • LC 1509. Minimum Difference Between Largest and Smallest Value in Three Moves

    • Approach 1: Full sorting + check result

    • Approach 2 (better): Partial sorting using heap + check result

  • 🌟 LC 295. Find Median from Data Stream

  • 🌟 LC 23. Merge k Sorted Lists

    • Approach 2 is better, but its implementation is trickier.

    • Approach 1 using Heap: Optimal Answerarrow-up-right.

      • Let NN be the total number of nodes and KK be the number of lists

        • TC: O(NlogK)O(N*log{K}), SC: O(K)O(K)

    • Approach 2 using Divide & Conquer: Optimal Answerarrow-up-right. TC: O(NlogK)O(N*log{K}), SC: O(1)O(1)

  • 🔴 LC 502. IPO

  • 🟠 LC 373. Find K Pairs with Smallest Sums

  • 🌟 🔴 LC 407. Trapping Rain Water II

    • Optimal Answer. TC: O(mnlog(mn))O(m*n*log(m*n)), SC: O(mn)O(m*n)

  • LC 2163. Minimum Difference in Sums After Removal of Elements

Last updated