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.
[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.[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
104
calls will be made to next
.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.
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:
Initialization: Create an empty stack.
next(price)
function:
span
to 1. This represents the span for the current day (at least the current day itself).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.(price, span)
pair onto the stack.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.
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.