问题描述
假设你是一名股票交易员,最近在关注某只股票的价格波动。给定该股票连续 N 天的价格列表 stockPrices,你需要生成一个新列表,每个位置的值表示从那天起至少需要等待多少天才能看到价格上涨。如果没有上涨的情况,则对应位置的值为0。
例如,对于股票价格列表 [33, 34, 14, 12, 16]:
- 从第一天价格 33 开始,价格上涨发生在第二天价格 34,所以输出 1。
- 如果某天之后不再有价格上涨,则输出 0。
示例
- 输入:
[33, 34, 14, 12, 16] - 输出:
[1, 0, 2, 1, 0] - 输入:
[45, 44, 46, 43, 42, 48] - 输出:
[2, 1, 3, 2, 1, 0] - 输入:
[10, 9, 8] - 输出:
[0, 0, 0]
问题分析
这个问题的核心在于找到每个价格之后第一个更高的价格的位置。直接的方法是使用两层循环,但对于较长的价格列表,这种方法的时间复杂度会非常高(O(N^2))。为了提高效率,我们可以使用单调栈来解决这个问题。
解决方案
下面是一个C++代码实现:
vector<int> solution(int N, vector<int>& stockPrices) {
vector<int> result(N, 0);
stack<pair<int, int>> s; // 存储价格和索引
// 从后向前遍历股票价格列表
for (int i = N - 1; i >= 0; --i) {
// 如果栈不为空且栈顶元素的价格小于等于当前价格
while (!s.empty() && s.top().first <= stockPrices[i]) {
s.pop();
}
// 如果栈不为空,说明找到了价格上涨的日期
if (!s.empty()) {
result[i] = s.top().second - i;
}
// 将当前价格及其索引压入栈中
s.push({stockPrices[i], i});
}
return result;
}
代码解释
-
初始化:
result是一个大小为N的向量,初始值为 0。s是一个栈,用于存储价格及其索引。
-
从后向前遍历:
- 从
N-1到0遍历股票价格列表。 - 对于每一天的价格,检查栈顶元素是否小于等于当前价格。如果是,则更新栈顶元素对应的等待天数,并弹出栈顶元素。
- 如果栈不为空,说明找到了价格上涨的日期,更新
result中对应的位置。 - 将当前价格及其索引压入栈中。
- 从
-
返回结果:
- 返回
result向量,其中每个位置的值表示从那一天起至少需要等待多少天才能看到价格上涨。
- 返回
技巧分享
-
单调栈:
- 单调栈是一种非常强大的数据结构,常用于解决涉及“下一个更大/更小”元素的问题。在这个问题中,我们使用单调递减栈来存储尚未找到上涨日期的价格及其索引。
- 通过从后向前遍历,我们可以确保每次遇到更高的价格时,栈中的所有更低价格都能被正确处理。
-
时间复杂度优化:
- 使用单调栈可以将时间复杂度从 O(N^2) 降低到 O(N),因为每个元素最多只会被压入和弹出栈一次。
-
空间复杂度:
- 由于我们使用了栈来存储价格及其索引,空间复杂度为 O(N)。虽然比直接方法多了一些空间开销,但这是为了换取时间效率。
总结
通过这个例子,我们学会了如何使用单调栈来高效地解决股票价格上涨天数问题。单调栈不仅适用于这个问题,还可以应用于许多其他类似的问题,如寻找下一个更大的元素、最长上升子序列等。