Bird
Raised Fist0
Interview Prepchallenge-problemshardAmazonFacebookGoogleBloomberg

Largest Rectangle in Histogram

Choose your preparation mode4 modes available
▶
Steps
setup

Initialize stack and max_area

We start with an empty stack and max_area set to 0. The input array is extended by appending a sentinel 0 height to ensure all bars are processed.

💡 Initializing max_area and stack prepares us to track the largest rectangle and the indices of bars in ascending height order.
Line:stack = [] max_area = 0 heights.append(0)
💡 The sentinel 0 at the end guarantees the stack will be emptied by the end of iteration.
📊
Largest Rectangle in Histogram - Watch the Algorithm Execute, Step by Step
Watching the stack operations and area calculations visually reveals how the algorithm efficiently finds the largest rectangle without checking all sub-rectangles.
Step 1/20
·Active fill★Answer cell
setup
2
0
1
1
5
2
6
3
2
4
3
5
0
6
Result: 0
move_right
stack
2
0
1
1
5
2
6
3
2
4
3
5
0
6
Result: 0
pop
2
0
i
1
1
5
2
6
3
2
4
3
5
0
6
Result: 0
record
2
0
i
1
1
5
2
6
3
2
4
3
5
0
6
Result: 2
move_right
2
0
stack
1
1
5
2
6
3
2
4
3
5
0
6
Result: 2
move_right
2
0
1
1
stack
5
2
6
3
2
4
3
5
0
6
Result: 2
move_right
2
0
1
1
5
2
stack
6
3
2
4
3
5
0
6
Result: 2
pop
2
0
1
1
stack
5
2
6
3
i
2
4
3
5
0
6
Result: 2
record
2
0
1
1
stack
5
2
6
3
i
2
4
3
5
0
6
Result: 6
pop
2
0
stack
1
1
5
2
6
3
i
2
4
3
5
0
6
Result: 6
record
2
0
stack
1
1
5
2
6
3
i
2
4
3
5
0
6
Result: 10
move_right
2
0
1
1
5
2
6
3
stack
2
4
3
5
0
6
Result: 10
move_right
2
0
1
1
5
2
6
3
2
4
stack
3
5
0
6
Result: 10
pop
2
0
1
1
5
2
6
3
stack
2
4
3
5
i
0
6
Result: 10
record
2
0
1
1
5
2
6
3
stack
2
4
3
5
i
0
6
Result: 10
pop
2
0
stack
1
1
5
2
6
3
2
4
3
5
i
0
6
Result: 10
record
2
0
stack
1
1
5
2
6
3
2
4
3
5
i
0
6
Result: 10
pop
2
0
1
1
5
2
6
3
2
4
3
5
i
0
6
Result: 10
record
2
0
1
1
5
2
6
3
2
4
3
5
i
0
6
Result: 10
return
2
0
1
1
5
2
6
3
2
4
3
5
Result: 10

Key Takeaways

✓ The stack maintains indices of bars in ascending height order, enabling efficient area calculations.

This insight is hard to see from code alone because the stack operations and their purpose are implicit without visualization.

✓ Popping bars when a shorter bar is encountered finalizes the largest rectangle for those bars.

Visualizing the popping and area calculation clarifies why the algorithm doesn't need to check all sub-rectangles.

✓ The sentinel 0 height at the end ensures all bars are processed and the stack is emptied.

Without the sentinel, the algorithm would need extra logic to finalize remaining bars; the sentinel simplifies the process.

Practice

(1/5)
1. Given the following code for largestRectangleArea, what is the returned max_area for input heights = [2,1,2]?
easy
A. 3
B. 4
C. 2
D. 1

Solution

  1. Step 1: Trace stack operations for heights=[2,1,2]

    i=0,h=2: stack=[0]; i=1,h=1: pop 0 (height=2,width=1), max_area=2; stack=[]; append 1; i=2,h=2: append 2; i=3,h=0: pop 2 (height=2,width=1), max_area=2; pop 1 (height=1,width=3), max_area=3
  2. Step 2: Final max_area after processing all elements

    max_area=3
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Max rectangle area is 3 for input [2,1,2] [OK]
Hint: Remember to add sentinel zero to flush stack [OK]
Common Mistakes:
  • Forgetting sentinel zero causes missed areas
  • Incorrect width calculation
  • Off-by-one in stack indices
2. Consider the following Python code implementing the optimal solution for Next Greater Element II. What is the final output when the input is [1, 2, 1]?
from typing import List

def nextGreaterElements(nums: List[int]) -> List[int]:
    n = len(nums)
    doubled = nums + nums
    answer = [-1] * n
    stack = []
    for i, num in enumerate(doubled):
        while stack and doubled[stack[-1]] < num:
            idx = stack.pop()
            if idx < n:
                answer[idx] = num
        if i < n:
            stack.append(i)
    return answer

print(nextGreaterElements([1,2,1]))
easy
A. [-1, 2, -1]
B. [2, -1, 2]
C. [2, 1, 2]
D. [2, 2, 2]

Solution

  1. Step 1: Trace stack and answer updates

    Initially, stack is empty. Iterate over doubled = [1,2,1,1,2,1]. - i=0, num=1: stack=[0] - i=1, num=2: 1 < 2, pop 0, answer[0]=2, stack=[]; push 1 -> stack=[1] - i=2, num=1: 2 > 1, push 2 -> stack=[1,2] - i=3, num=1: push 3 (ignored since i≥n) - i=4, num=2: pop 2 (answer[2]=2), pop 1 (answer[1]=2), stack=[] - i=5, num=1: push 5 (ignored)
  2. Step 2: Final answer array

    answer = [2, -1, 2] because answer[1] was updated only when popping index 1 at i=4, but since i=4≥n, answer update only occurs if idx < n, so answer[1] remains -1.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Output matches expected next greater elements for circular array [OK]
Hint: Stack pops update answer only for indices < n [OK]
Common Mistakes:
  • Updating answer for indices ≥ n causing duplicates
  • Misreading when to push indices onto stack
  • Confusing values and indices in stack
3. What is the time complexity of the getMin() operation in the single stack with encoded minimum values approach for the Minimum Stack problem, and why?
medium
A. O(1), because the minimum value is stored and updated during push and pop operations.
B. O(n), because it needs to scan the entire stack to find the minimum.
C. O(log n), because the stack maintains a balanced structure to track minimums.
D. O(n), because the encoded differences require decoding all elements to find the minimum.

Solution

  1. Step 1: Understand getMin() operation

    In the encoded stack approach, minVal is updated on every push/pop, so getMin() just returns minVal.
  2. Step 2: Analyze complexity

    Since getMin() returns a stored variable without iteration, it runs in O(1) time.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    getMin() is a direct variable access, no loops [OK]
Hint: getMin() returns stored minVal updated on push/pop [OK]
Common Mistakes:
  • Assuming getMin scans stack
  • Confusing encoded values require decoding
  • Thinking balanced tree needed for min tracking
4. Suppose the problem is modified so that the input string can contain not only '(' and ')' but also '*' characters, where '*' can represent either '(' or ')' or an empty string. Which approach is best suited to handle this variant efficiently?
hard
A. Use dynamic programming to track valid substring lengths considering '*' as wildcards.
B. Use the two-pass counter approach ignoring '*' characters.
C. Use brute force checking all substrings and validating with '*' replacements.
D. Use a stack-based approach tracking indices and possible '*' substitutions.

Solution

  1. Step 1: Understand the complexity introduced by '*'

    The '*' character can represent multiple possibilities, requiring tracking multiple states.
  2. Step 2: Evaluate approaches for handling wildcards

    Dynamic programming can efficiently track valid substring lengths considering '*' as '(', ')' or empty, unlike counters or naive stack approaches.
  3. Step 3: Rule out brute force due to exponential possibilities

    Brute force checking all substrings with '*' replacements is infeasible for large inputs.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    DP handles wildcard substitutions efficiently [OK]
Hint: DP handles wildcard '*' efficiently [OK]
Common Mistakes:
  • Ignoring '*' in counters
  • Assuming stack alone can handle wildcards
  • Trying brute force for large inputs
5. Suppose the problem is modified so that the array is circular and you want to find the next greater element allowing repeated reuse of elements (i.e., you can wrap around multiple times). Which modification to the monotonic stack approach correctly handles this variant?
hard
A. Modify the stack to store values instead of indices to handle repeated reuse
B. Use a brute force nested loop with modulo indexing to simulate infinite wrap
C. Extend the doubled array to triple or more copies and run the same monotonic stack algorithm
D. Use a queue instead of a stack to process elements in order for multiple wraps

Solution

  1. Step 1: Understand problem variant

    Allowing repeated reuse means next greater element might appear after multiple wraps, not just one.
  2. Step 2: Modify approach accordingly

    Extending the array to triple or more copies simulates multiple wraps, allowing monotonic stack to find next greater elements beyond one wrap.
  3. Step 3: Why other options fail

    Brute force is inefficient; storing values loses index mapping; queue does not maintain monotonic property needed.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Extending array copies simulates multiple wraps correctly [OK]
Hint: Multiple wraps -> extend array copies accordingly [OK]
Common Mistakes:
  • Using brute force which is inefficient
  • Storing values instead of indices losing position info
  • Replacing stack with queue losing monotonic property
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard