持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情
题目
编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。
今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。
例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]。
示例:
输入:["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%。
思考
本题难度中等。
首先是读懂题意。 编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。
我们注意到,跨度被定义为股票价格小于或等于今天价格的最大连续日数。因此,我们可以借助单调栈来解题。这里使用的是单调递减的栈。
我们在栈中存入由索引和股票价格组成的数组。对于栈中的第一个元素,初始化时我们存入[-1, Number.MAX_VALUE]。
当存入新的价格时,与栈中最后一个元素比较大小,如果当前价格 >= 栈中最后一个元素的价格,则弹出栈中最后一个元素,并继续判断。返回值是当前价格的索引减去栈中最后一个元素的索引。
解答
方法一:单调栈
var StockSpanner = function() {
this.idx = -1 // 索引
this.stack = [] // 栈:栈中数字是从大到小排列
this.stack.push([-1, Number.MAX_VALUE]) // push第一个数,0-(-1)=1
}
/**
* @param {number} price
* @return {number}
*/
StockSpanner.prototype.next = function(price) {
this.idx++
while (price >= this.stack[this.stack.length - 1][1]) {
this.stack.pop()
}
// console.log(this.idx, this.stack)
let ans = this.idx - this.stack[this.stack.length - 1][0]
this.stack.push([this.idx, price])
return ans
}
复杂度分析:
- 时间复杂度:O(n),其中 n 为调用 next 函数的次数,每个 price 都会入栈和出栈各 1 次。
- 空间复杂度:O(n)。