🧠
Using Monotonic Stack (Stack of Pairs)
💡 This approach uses a stack to keep track of prices and their spans, allowing us to skip multiple previous days at once, drastically improving efficiency.
Intuition
Maintain a stack of pairs (price, span) where prices are in decreasing order. For each new price, pop all prices less or equal to it and accumulate their spans to get the current span.
Algorithm
- Initialize an empty stack to store pairs of (price, span).
- For each new price, initialize span as 1.
- While the stack is not empty and the top price is less or equal to current price, pop it and add its span to current span.
- Push the current price and its span onto the stack.
- Return the current span.
💡 This algorithm cleverly skips multiple previous days by aggregating spans, avoiding repeated comparisons.
class StockSpanner:
def __init__(self):
self.stack = [] # pair: (price, span)
def next(self, price: int) -> int:
span = 1
while self.stack and self.stack[-1][0] <= price:
span += self.stack.pop()[1]
self.stack.append((price, span))
return span
# Example usage:
# spanner = StockSpanner()
# print([spanner.next(p) for p in [100, 80, 60, 70, 60, 75, 85]])
Line Notes
self.stack = []Stack stores pairs of (price, span) to aggregate spans efficiently and skip multiple days
span = 1Start span at 1 for the current day as it counts itself
while self.stack and self.stack[-1][0] <= price:Pop all prices less or equal to current price to accumulate their spans
self.stack.append((price, span))Push current price and its total span for future calculations
return spanReturn the calculated span for current price
import java.util.*;
class StockSpanner {
private Deque<int[]> stack; // stores pairs {price, span}
public StockSpanner() {
stack = new ArrayDeque<>();
}
public int next(int price) {
int span = 1;
while (!stack.isEmpty() && stack.peek()[0] <= price) {
span += stack.pop()[1];
}
stack.push(new int[]{price, span});
return span;
}
// Example usage:
// public static void main(String[] args) {
// StockSpanner spanner = new StockSpanner();
// int[] prices = {100, 80, 60, 70, 60, 75, 85};
// for (int p : prices) System.out.print(spanner.next(p) + " ");
// }
}
Line Notes
stack = new ArrayDeque<>()Stack stores pairs of price and span for efficient aggregation and skipping
int span = 1;Initialize span for current price including itself
while (!stack.isEmpty() && stack.peek()[0] <= price)Pop all smaller or equal prices to accumulate their spans
stack.push(new int[]{price, span});Push current price and its span for future calls
return span;Return the calculated span
#include <iostream>
#include <stack>
using namespace std;
class StockSpanner {
stack<pair<int,int>> st; // pair: (price, span)
public:
StockSpanner() {}
int next(int price) {
int span = 1;
while (!st.empty() && st.top().first <= price) {
span += st.top().second;
st.pop();
}
st.push({price, span});
return span;
}
};
// Example usage:
// int main() {
// StockSpanner spanner;
// int prices[] = {100, 80, 60, 70, 60, 75, 85};
// for (int p : prices) cout << spanner.next(p) << " ";
// return 0;
// }
Line Notes
stack<pair<int,int>> st;Stack stores pairs of price and span to aggregate spans efficiently and skip multiple days
int span = 1;Start span at 1 for current price including itself
while (!st.empty() && st.top().first <= price)Pop all smaller or equal prices to add their spans
st.push({price, span});Push current price and its span for future queries
return span;Return the calculated span
class StockSpanner {
constructor() {
this.stack = []; // stores pairs [price, span]
}
next(price) {
let span = 1;
while (this.stack.length > 0 && this.stack[this.stack.length - 1][0] <= price) {
span += this.stack.pop()[1];
}
this.stack.push([price, span]);
return span;
}
}
// Example usage:
// const spanner = new StockSpanner();
// console.log([100, 80, 60, 70, 60, 75, 85].map(p => spanner.next(p)));
Line Notes
this.stack = []Stack stores pairs of price and span for efficient span calculation and skipping multiple days
let span = 1;Initialize span for current price including itself
while (this.stack.length > 0 && this.stack[this.stack.length - 1][0] <= price)Pop smaller or equal prices to accumulate spans
this.stack.push([price, span]);Push current price and its span for future calls
return span;Return the calculated span
Each price is pushed and popped at most once, so total operations are linear. Space stores stack elements up to n.
💡 For n=100000, this means about 200000 operations, which is efficient and feasible.
Interview Verdict: Accepted
This approach is optimal and passes all tests efficiently, making it the preferred solution.