设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。
当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。
-
例如,如果未来 7 天股票的价格是
[100,80,60,70,60,75,85]
,那么股票跨度将是[1,1,1,2,1,4,6]
。
实现 StockSpanner
类:
StockSpanner()
初始化类对象。int next(int price)
给出今天的股价price
,返回该股票当日价格的 跨度 。
示例:
输入: ["StockSpanner", "next", "next", "next", "next", "next", "next", "next"] [[], [100], [80], [60], [70], [60], [75], [85]] 输出: [null, 1, 1, 1, 2, 1, 4, 6] 解释: StockSpanner stockSpanner = new StockSpanner(); stockSpanner.next(100); // 返回 1 stockSpanner.next(80); // 返回 1 stockSpanner.next(60); // 返回 1 stockSpanner.next(70); // 返回 2 stockSpanner.next(60); // 返回 1 stockSpanner.next(75); // 返回 4 ,因为截至今天的最后 4 个股价 (包括今天的股价 75) 都小于或等于今天的股价。 stockSpanner.next(85); // 返回 6
提示:
1 <= price <= 105
- 最多调用
next
方法104
次
class StockSpanner {
// 使用双端队列(栈)来存储股票价格和它们的索引
Deque<int[]> stack;
// 当前的股票价格索引
int idx;
/**
* 构造函数,初始化一个空栈和一个索引。
*/
public StockSpanner() {
// 初始化栈,并将一个特殊的初始元素(-1,最大整数值)推入栈中
stack = new ArrayDeque<int[]>();
stack.push(new int[]{-1, Integer.MAX_VALUE});
idx = -1;
}
/**
* 处理下一个价格,并返回自上一个价格起价格不低于当前价格的天数。
* @param price 当前股票价格
* @return 自上一个价格起价格不低于当前价格的天数
*/
public int next(int price) {
// 更新当前的股票价格索引
idx++;
// 只要栈顶的价格小于等于当前价格,就弹出栈顶元素
// 这是因为我们要找到第一个价格不低于当前价格的天数
while (price >= stack.peek()[1]) {
stack.pop();
}
// 计算当前价格的跨度(即价格不低于当前价格的天数)
int ret = idx - stack.peek()[0];
// 将当前价格及其索引推入栈中
stack.push(new int[]{idx, price});
// 返回计算得到的天数
return ret;
}
}
解题思路
-
数据结构选择:
- 使用一个双端队列(
Deque
)作为栈来存储价格和对应的索引。栈的使用允许我们高效地访问和更新最近的价格数据。
- 使用一个双端队列(
-
初始化:
- 在构造函数
StockSpanner
中,初始化一个空的栈,并将一个特殊的初始元素({-1, Integer.MAX_VALUE}
)推入栈中。这个元素用来简化边界条件的处理(即计算跨度时的基准值)。
- 在构造函数
-
处理价格:
- 在
next
方法中,首先更新股票价格的索引。 - 然后,使用
while
循环,检查栈顶的价格是否小于或等于当前价格。如果是,弹出栈顶的元素,因为这些元素都不能作为答案。 - 计算当前价格的跨度。这个跨度是当前索引与栈顶元素索引之间的差值。
- 最后,将当前的价格及其索引推入栈中,并返回计算出的跨度值。
- 在
主要操作
push
: 将当前价格和索引入栈。pop
: 移除栈顶元素,直到找到一个价格大于当前价格的元素。- 计算跨度: 使用当前的索引和栈顶的索引计算天数差,得到跨度。