{x}
blog image

Online Stock Span

Design an algorithm that collects daily price quotes for some stock and returns the span of that stock's price for the current day.

The span of the stock's price in one day is the maximum number of consecutive days (starting from that day and going backward) for which the stock price was less than or equal to the price of that day.

  • For example, if the prices of the stock in the last four days is [7,2,1,2] and the price of the stock today is 2, then the span of today is 4 because starting from today, the price of the stock was less than or equal 2 for 4 consecutive days.
  • Also, if the prices of the stock in the last four days is [7,34,1,2] and the price of the stock today is 8, then the span of today is 3 because starting from today, the price of the stock was less than or equal 8 for 3 consecutive days.

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.

 

Example 1:

Input
["StockSpanner", "next", "next", "next", "next", "next", "next", "next"]
[[], [100], [80], [60], [70], [60], [75], [85]]
Output
[null, 1, 1, 1, 2, 1, 4, 6]

Explanation
StockSpanner stockSpanner = new StockSpanner();
stockSpanner.next(100); // return 1
stockSpanner.next(80);  // return 1
stockSpanner.next(60);  // return 1
stockSpanner.next(70);  // return 2
stockSpanner.next(60);  // return 1
stockSpanner.next(75);  // return 4, because the last 4 prices (including today's price of 75) were less than or equal to today's price.
stockSpanner.next(85);  // return 6

 

Constraints:

  • 1 <= price <= 105
  • At most 104 calls will be made to next.

Solution Explanation: Online Stock Span

This problem requires designing a data structure that efficiently calculates the stock span for each day. The stock span is defined as the maximum number of consecutive days (including the current day) where the stock price was less than or equal to the current day's price.

Approach: Monotonic Stack

The most efficient approach uses a monotonic stack. A monotonic stack is a stack that maintains a specific order (either strictly increasing or strictly decreasing). In this case, we'll use a decreasing monotonic stack.

The stack will store pairs of (price, span). The price is the stock price on a particular day, and span is the span calculated for that day.

Algorithm:

  1. Initialization: Create an empty stack.

  2. next(price) function:

    • Initialize span to 1. This represents the span for the current day (at least the current day itself).
    • While loop: While the stack is not empty and the top element's price is less than or equal to the current price, pop the top element. Add the popped element's span to the current span. This signifies that the current price is greater than the previous days and thus the span extends.
    • Push: Push the (price, span) pair onto the stack.
    • Return: Return the calculated span.

Time Complexity: O(N), where N is the number of calls to the next function. In the worst case, each call to next might iterate through the entire stack, but each element is pushed and popped at most once.

Space Complexity: O(N), in the worst case, the stack might store all the price-span pairs processed so far.

Code Examples (with explanations):

The code implementations in different languages demonstrate the algorithm:

Python:

class StockSpanner:
    def __init__(self):
        self.stk = [] # Initialize an empty stack to store (price, span) pairs
 
    def next(self, price: int) -> int:
        cnt = 1 # Initialize the span for current day to 1
        while self.stk and self.stk[-1][0] <= price: # Check the stack and pop elements if the condition is met
            cnt += self.stk.pop()[1] # Add the span of the popped element to current span
        self.stk.append((price, cnt)) # Push the current (price, span) onto the stack
        return cnt # Return the calculated span

Java:

import java.util.Deque;
import java.util.ArrayDeque;
 
class StockSpanner {
    private Deque<int[]> stk = new ArrayDeque<>(); //Use Deque for stack operations
 
    public int next(int price) {
        int cnt = 1;
        while (!stk.isEmpty() && stk.peek()[0] <= price) {
            cnt += stk.pop()[1];
        }
        stk.push(new int[] {price, cnt});
        return cnt;
    }
}

The Java and other language implementations follow the same logic as the Python code, using the appropriate data structures for stacks in their respective languages. The core algorithm remains consistent. Note the use of Deque in Java for efficient stack operations. Other languages use similar stack implementations (e.g., stack in C++, VecDeque in Rust).

This monotonic stack approach provides an efficient and elegant solution to the Online Stock Span problem, optimizing both time and space complexity.