一、题目描述
编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。
今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。
例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]。
来源:力扣(LeetCode)
链接:股票价格跨度
示例:
输入:["StockSpanner","next","next","next","next","next","next","next"], [[],[100],[80],[60],[70],[60],[75],[85]]
输出:[null,1,1,1,2,1,4,6]
解释:
首先,初始化 S = StockSpanner(),然后:
S.next(100) 被调用并返回 1,
S.next(80) 被调用并返回 1,
S.next(60) 被调用并返回 1,
S.next(70) 被调用并返回 2,
S.next(60) 被调用并返回 1,
S.next(75) 被调用并返回 4,
S.next(85) 被调用并返回 6。
注意 (例如) S.next(75) 返回 4,因为截至今天的最后 4 个价格
(包括今天的价格 75) 小于或等于今天的价格。
提示:
- 调用 StockSpanner.next(int price) 时,将有 1 <= price <= 10^5。
- 每个测试用例最多可以调用 10000 次 StockSpanner.next。
- 在所有测试用例中,最多调用 150000 次 StockSpanner.next。
- 此问题的总时间限制减少了 50%。
二、解题思路
寻找小于或等于今日价格可以等价转换为寻找最近的大于今天股票价格的日期,因此本题采用单调栈的方法,维护一个从栈底到栈顶单调递减的栈。设 第i天的价格为 A[i],第j天的价格为A[j],满足i<j 且A[i]<=A[j],那么第j天之后的结果不会受第i天的影响(假设第i天是首个大于今天的价格的日期,那么显然与A[i]<=A[j] 且i<j 矛盾)。
我们还需要为每一个价格存储一个weight,用来存储距离上一个股票价格的天数(即 距离最近的大于该股票价格的日期 的天数)。
算法思路如下:
我们维护一个单调递减的栈,对于新的股票价格:
1、栈中所有小于当前股票价格的元素出栈,并把出栈的元素的weight值累加
2、weight+1,当前股票价格跟weight一块入栈。
代码如下:
class StockSpanner {
private Stack<Stock> stack;
public StockSpanner() {
stack=new Stack<Stock>();
}
public int next(int price) {
int w=1;
while(!stack.isEmpty() && stack.peek().price<=price){
Stock stock=stack.pop();
w=w+stock.weight;
}
Stock stock=new Stock(price,w);
stack.push(stock);
return w;
}
}
class Stock
{
protected int price;
protected int weight;
public Stock(int price,int weight){
this.price=price;
this.weight=weight;
}
}
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner obj = new StockSpanner();
* int param_1 = obj.next(price);
*/