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. Consider the following Python code implementing the optimal 132 pattern detection algorithm. What is the return value when the input is [3, 1, 4, 2]?
easy
A. None
B. False
C. Raises an error
D. True

Solution

  1. Step 1: Trace the loop with input [3,1,4,2]

    Iterate reversed: 2,4,1,3. Initially, stack=[], third=-inf. - num=2: stack empty, append 2. - num=4: stack top 2 < 4, pop 2, third=2, append 4. - num=1: 1 < third(2), return True.
  2. Step 2: Confirm early return

    At num=1, condition triggers return True, so output is True.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Early return on detecting 132 pattern confirmed [OK]
Hint: Early return when num < third triggers True [OK]
Common Mistakes:
  • Confusing iteration order
  • Misunderstanding when third updates
  • Off-by-one in stack operations
2. Consider the following Python code that evaluates Reverse Polish Notation expressions. What is the final output when the input tokens are ["4", "13", "5", "/", "+"]?
class Solution:
    def evalRPN(self, tokens):
        import operator
        ops = {
            '+': operator.add,
            '-': operator.sub,
            '*': operator.mul,
            '/': lambda x, y: int(x / y),
        }
        stack = []
        for token in tokens:
            if token in ops:
                right = stack.pop()
                left = stack.pop()
                stack.append(ops[token](left, right))
            else:
                stack.append(int(token))
        return stack.pop()

sol = Solution()
print(sol.evalRPN(["4", "13", "5", "/", "+"]))
easy
A. 2
B. 6
C. 8
D. 10

Solution

  1. Step 1: Trace stack operations

    Push 4, push 13, push 5; then '/' operator pops 5 and 13, computes int(13/5) = 2, push 2; then '+' operator pops 2 and 4, computes 4+2=6, push 6.
  2. Step 2: Final stack pop

    Pop the last element 6 as the result.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Stack correctly reflects intermediate results [OK]
Hint: Remember integer division truncates toward zero [OK]
Common Mistakes:
  • Swapping left and right operands
  • Using float division instead of int
  • Off-by-one in stack pops
3. You are given an array representing the heights of adjacent bars in a histogram. Your task is to find the largest rectangular area that can be formed within the bounds of the histogram bars. Which algorithmic approach guarantees an optimal O(n) time solution for this problem?
easy
A. Greedy approach expanding from each bar until a smaller bar is found
B. Dynamic programming with memoization over all sub-intervals
C. Monotonic stack to find the nearest smaller bars on left and right boundaries
D. Sorting bars by height and using binary search to find boundaries

Solution

  1. Step 1: Understand problem constraints

    The problem requires finding the largest rectangle in a histogram efficiently, which involves quickly determining boundaries for each bar.
  2. Step 2: Identify the approach that finds boundaries in O(n)

    Monotonic stack efficiently finds nearest smaller bars on both sides in linear time, enabling calculation of max area.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Monotonic stack approach is well-known for O(n) solution [OK]
Hint: Monotonic stack finds boundaries in linear time [OK]
Common Mistakes:
  • Assuming greedy expansion is always optimal
  • Thinking DP over all intervals is efficient here
4. You are given two arrays nums1 and nums2, where nums1 is a subset of nums2. For each element in nums1, you want to find the first greater element to its right in nums2. Which algorithmic approach guarantees an optimal solution in terms of time complexity?
easy
A. Use a monotonic stack to precompute the next greater element for all elements in nums2, then map results for nums1.
B. Use nested loops to check each element of nums1 against all elements to its right in nums2.
C. Use dynamic programming to store the next greater element for each index in nums2.
D. Sort nums2 and use binary search to find the next greater element for each element in nums1.

Solution

  1. Step 1: Understand the problem constraints

    The problem requires finding the next greater element for each element in nums1 based on their positions in nums2, which is a classic next greater element problem.
  2. Step 2: Identify the optimal approach

    Using a monotonic stack to precompute next greater elements for all nums2 elements allows O(n) processing, then mapping results for nums1 is O(m), leading to an overall O(n + m) time complexity.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Monotonic stack approach is well-known for next greater element problems [OK]
Hint: Monotonic stack precomputes next greater efficiently [OK]
Common Mistakes:
  • Using nested loops leads to O(m*n) time, too slow for large inputs
  • Sorting nums2 loses original order, invalidating next greater logic
  • Dynamic programming is not applicable here as no overlapping subproblems
5. The following code attempts to solve the Next Greater Element II problem using a monotonic stack and explicit circular array copy. Identify the line containing the subtle bug that causes incorrect results on some inputs.
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)  # Bug here
    return answer
medium
A. Line pushing indices onto stack only when i < n
B. Line popping from stack while top element is less than current num
C. Line initializing answer array with -1
D. Line creating doubled array by concatenation

Solution

  1. Step 1: Understand stack push condition

    Only pushing indices when i < n means indices from second pass (i ≥ n) are never pushed, so some elements' next greater values are missed.
  2. Step 2: Identify correct push strategy

    To simulate circular array correctly, indices should be pushed for the entire doubled array, or a different approach used. Restricting push to i < n causes missing updates.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Bug is in restricting stack pushes to first pass only [OK]
Hint: Pushing indices only in first pass misses circular wrap [OK]
Common Mistakes:
  • Not pushing indices in second pass causing incomplete updates
  • Using values instead of indices in stack
  • Not initializing answer array with -1
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