Bird
Raised Fist0
Interview Prepstacks-monotonic-stackmediumAmazonGoogle

Online Stock Span

Choose your preparation mode4 modes available
📋
Problem

Imagine you're a stock trader who wants to quickly know how many consecutive days the stock price has been less than or equal to today's price, to gauge momentum.

Design a class StockSpanner that collects daily stock prices and returns the span of the stock's price for the current day. The span of the stock's price today is defined as the maximum number of consecutive days (starting from today and going backwards) for which the price of the stock was less than or equal to today's price. Implement the StockSpanner class: - StockSpanner() Initializes the object of the class. - int next(int price) Returns the span of the stock's price given that today's price is price.

1 ≤ price ≤ 10^5At most 10^5 calls will be made to next.
Edge cases: Only one price input → span is always 1Strictly increasing prices → span equals current day index + 1Strictly decreasing prices → span always 1
</>
IDE
def next(self, price: int) -> int:public int next(int price)int next(int price)function next(price)
class StockSpanner:
    def __init__(self):
        # Write your solution here
        pass
    
    def next(self, price: int) -> int:
        pass
class StockSpanner {
    public StockSpanner() {
        // Write your solution here
    }
    public int next(int price) {
        // Write your solution here
        return 0;
    }
}
#include <vector>
using namespace std;

class StockSpanner {
public:
    StockSpanner() {
        // Write your solution here
    }
    int next(int price) {
        // Write your solution here
        return 0;
    }
};
class StockSpanner {
    constructor() {
        // Write your solution here
    }
    next(price) {
        // Write your solution here
    }
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: [1, 1, 1, 1, 1, 1, 1]Not popping previous prices less or equal to current price, always returning 1.✅ Pop from stack while top price <= current price and sum their spans before pushing current price.
Wrong: [1, 2, 3, 4, 1]Incorrectly resetting span after a local decrease instead of continuing to pop all smaller or equal prices.✅ Ensure popping continues while top price <= current price, not just immediate previous price.
Wrong: [1, 1, 1, 2, 1, 1, 1]Not accumulating spans from popped elements, only counting current price as span 1.✅ Accumulate spans from all popped elements and add 1 for current price before pushing.
Wrong: TLE or timeoutUsing brute force nested loops scanning all previous prices for each next call.✅ Implement monotonic stack to achieve O(n) time complexity by pushing and popping prices once.
✓
Test Cases
t1_01basic
Input{"calls":["next(100)","next(80)","next(60)","next(70)","next(60)","next(75)","next(85)"]}
Expected[1,1,1,2,1,4,6]

For each price, the span counts consecutive previous days with price less or equal to current price. For example, for price 75, previous prices 60, 70, 60 are less or equal, so span is 4.

t1_02basic
Input{"calls":["next(31)","next(41)","next(48)","next(59)","next(79)"]}
Expected[1,2,3,4,5]

Strictly increasing prices cause spans to increase by 1 each day, so spans are [1,2,3,4,5].

t2_01edge
Input{"calls":["next(50)"]}
Expected[1]

Single price input always has span 1.

t2_02edge
Input{"calls":["next(100)","next(90)","next(80)","next(70)","next(60)"]}
Expected[1,1,1,1,1]

Strictly decreasing prices always have span 1 because no previous price is less or equal.

t2_03edge
Input{"calls":["next(20)","next(20)","next(20)","next(20)"]}
Expected[1,2,3,4]

All equal prices cause spans to increase cumulatively as all previous prices are less or equal.

t3_01corner
Input{"calls":["next(100)","next(80)","next(60)","next(70)","next(60)","next(75)","next(85)","next(90)"]}
Expected[1,1,1,2,1,4,6,7]

Tests correct span after multiple pops and cumulative sums; last price 90 spans 7 days including previous prices less or equal.

t3_02corner
Input{"calls":["next(10)","next(20)","next(15)","next(25)","next(5)"]}
Expected[1,2,1,4,1]

Tests non-monotonic sequence with local decreases; span resets correctly after price drops.

t3_03corner
Input{"calls":["next(50)","next(50)","next(40)","next(60)","next(60)"]}
Expected[1,2,1,4,5]

Tests handling of equal prices interspersed with lower prices; spans accumulate correctly.

t4_01performance
Input{"calls":["next(100000)","next(99999)","next(99998)","next(99997)","next(99996)","next(99995)","next(99994)","next(99993)","next(99992)","next(99991)","next(99990)","next(99989)","next(99988)","next(99987)","next(99986)","next(99985)","next(99984)","next(99983)","next(99982)","next(99981)","next(99980)","next(99979)","next(99978)","next(99977)","next(99976)","next(99975)","next(99974)","next(99973)","next(99972)","next(99971)","next(99970)","next(99969)","next(99968)","next(99967)","next(99966)","next(99965)","next(99964)","next(99963)","next(99962)","next(99961)","next(99960)","next(99959)","next(99958)","next(99957)","next(99956)","next(99955)","next(99954)","next(99953)","next(99952)","next(99951)","next(99950)","next(99949)","next(99948)","next(99947)","next(99946)","next(99945)","next(99944)","next(99943)","next(99942)","next(99941)","next(99940)","next(99939)","next(99938)","next(99937)","next(99936)","next(99935)","next(99934)","next(99933)","next(99932)","next(99931)","next(99930)","next(99929)","next(99928)","next(99927)","next(99926)","next(99925)","next(99924)","next(99923)","next(99922)","next(99921)","next(99920)","next(99919)","next(99918)","next(99917)","next(99916)","next(99915)","next(99914)","next(99913)","next(99912)","next(99911)","next(99910)","next(99909)","next(99908)","next(99907)","next(99906)","next(99905)","next(99904)","next(99903)","next(99902)","next(99901)","next(99900)","next(99899)","next(99898)","next(99897)","next(99896)","next(99895)","next(99894)","next(99893)","next(99892)","next(99891)","next(99890)","next(99889)","next(99888)","next(99887)","next(99886)","next(99885)","next(99884)","next(99883)","next(99882)","next(99881)","next(99880)","next(99879)","next(99878)","next(99877)","next(99876)","next(99875)","next(99874)","next(99873)","next(99872)","next(99871)","next(99870)","next(99869)","next(99868)","next(99867)","next(99866)","next(99865)","next(99864)","next(99863)","next(99862)","next(99861)","next(99860)","next(99859)","next(99858)","next(99857)","next(99856)","next(99855)","next(99854)","next(99853)","next(99852)","next(99851)","next(99850)"]}
⏱ Performance - must finish in 2000ms

Performance test with n=100 calls of strictly decreasing prices to ensure O(n) monotonic stack solution runs within 2 seconds.

Practice

(1/5)
1. Given the following Python code for the Basic Calculator, what is the value of result immediately after processing the character ')' at index 6 in the input string "(1+(2-3))"?
def calculate(s: str) -> int:
    stack = []
    result = 0
    sign = 1
    num = 0
    for i, c in enumerate(s):
        if c.isdigit():
            num = num * 10 + int(c)
        elif c in '+-':
            result += sign * num
            num = 0
            sign = 1 if c == '+' else -1
        elif c == '(':  # Push current result and sign
            stack.append(result)
            stack.append(sign)
            result = 0
            sign = 1
        elif c == ')':  # Add last number and combine
            result += sign * num
            num = 0
            result *= stack.pop()
            result += stack.pop()
    result += sign * num
    return result
easy
A. 0
B. 0
C. 0
D. 0

Solution

  1. Step 1: Trace characters up to index 6

    Input: "(1+(2-3))" - i=0:'(' push 0 and 1, result=0, sign=1 - i=1:'1' num=1 - i=2:'+' result=0+1*1=1, num=0, sign=1 - i=3:'(' push 1 and 1, result=0, sign=1 - i=4:'2' num=2 - i=5:'-' result=0+1*2=2, num=0, sign=-1 - i=6:'3' num=3
  2. Step 2: Process character at index 6 (')')

    At ')': result += sign*num = 2 + (-1)*3 = -1 num=0 result *= stack.pop() -> result *= 1 -> -1 result += stack.pop() -> -1 + 1 = 0
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Result after popping stack is 0 [OK]
Hint: Remember to apply sign*num before popping stack [OK]
Common Mistakes:
  • Forgetting to add last number before popping stack
2. Consider the following Python function implementing the optimized monotonic stack approach for sum of subarray minimums. What is the final returned value when calling sumSubarrayMins([3,1,2,4])?
easy
A. 17
B. 15
C. 14
D. 10

Solution

  1. Step 1: Trace stack operations for input [3,1,2,4]

    Push indices 0(3), then at i=1(1), pop 0 because 1<3, add 3*(1-(-1))*(1-0)=3*1*1=3; push 1. Continue similarly for indices 2 and 3.
  2. Step 2: Calculate final result after processing sentinel

    After processing all elements and sentinel, sum is 17 modulo 10^9+7.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Matches known correct output for this input [OK]
Hint: Sentinel ensures all elements processed; final sum is 17 [OK]
Common Mistakes:
  • Off-by-one in counting subarrays
  • Forgetting sentinel element
3. What is the time complexity of the optimized stack simulation algorithm for the asteroid collision problem, given n asteroids in the input list?
medium
A. O(n) because each asteroid is pushed and popped at most once
B. O(n log n) due to sorting implicit in stack operations
C. O(n^2) because each asteroid can cause multiple pops in the stack
D. O(n) for iteration plus O(n) for auxiliary space, total O(n)

Solution

  1. Step 1: Analyze iteration over asteroids

    The algorithm iterates over each asteroid once.
  2. Step 2: Analyze stack operations

    Each asteroid can be pushed once and popped once, so total stack operations are O(n).
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Each asteroid processed at most twice (push/pop) [OK]
Hint: Each asteroid pushed and popped once max [OK]
Common Mistakes:
  • Assuming nested while loop causes O(n^2)
  • Confusing stack operations with sorting
  • Ignoring amortized analysis of stack pops
4. The following code attempts to compute the largest rectangle area in a histogram using a monotonic stack. Identify the line containing the subtle bug that causes incorrect area calculation in some cases.
def largestRectangleArea(heights):
    n = len(heights)
    left = [-1] * n
    right = [n] * n
    stack = []

    for i in range(n):
        while stack and heights[stack[-1]] >= heights[i]:
            stack.pop()
        left[i] = stack[-1] if stack else -1
        stack.append(i)

    stack.clear()

    for i in range(n - 1, -1, -1):
        while stack and heights[stack[-1]] >= heights[i]:
            stack.pop()
        right[i] = stack[-1] if stack else n
        stack.append(i)

    max_area = 0
    for i in range(n):
        width = right[i] - left[i] - 1
        area = heights[i] * width
        max_area = max(max_area, area)
    return max_area
medium
A. Line with 'while stack and heights[stack[-1]] >= heights[i]:' in right boundary computation
B. Line with 'stack.clear()' before computing right boundaries
C. Line with 'width = right[i] - left[i] - 1' in area calculation
D. Line with 'while stack and heights[stack[-1]] > heights[i]:' in left boundary computation

Solution

  1. Step 1: Compare left boundary condition with right boundary

    Left boundary uses '>=' but right boundary also uses '>='; originally left boundary used '>' causing inconsistency.
  2. Step 2: Identify impact of using '>' instead of '>='

    Using '>' misses popping bars equal in height, leading to wrong left boundaries and smaller area.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Changing '>' to '>=' in left boundary fixes the bug [OK]
Hint: Use consistent '>=' in both boundary computations [OK]
Common Mistakes:
  • Mixing '>' and '>=' causing inconsistent boundaries
  • Forgetting to clear stack before right boundary pass
5. Suppose you want to extend the one-queue stack implementation to support a multiPop(k) operation that pops the top k elements at once. Which modification maintains correct stack order and efficient operations?
hard
A. Perform k consecutive pop() calls on the queue, each O(1), total O(k).
B. Modify push to rotate the queue k times after each push to prepare for multiPop.
C. Use two queues instead, transferring elements to support batch pop efficiently.
D. Store elements in a separate stack data structure internally to support multiPop efficiently.

Solution

  1. Step 1: Understand multiPop operation

    multiPop(k) means popping top k elements in stack order.
  2. Step 2: Analyze one-queue approach

    Since pop is O(1), performing k pops consecutively is O(k) and maintains order.
  3. Step 3: Evaluate other options

    Rotating queue k times after push breaks order; two queues add complexity; using stack internally violates constraints.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Consecutive pops maintain order and are efficient in one-queue approach [OK]
Hint: multiPop(k) = k consecutive O(1) pops in one-queue stack [OK]
Common Mistakes:
  • Trying to rotate queue multiple times per push unnecessarily
  • Switching to two queues without reason
  • Using stack internally violating problem constraints
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