leetcode
leetcode 801 ~ 850
股票价格跨度

股票价格跨度

难度:

标签:

题目描述

代码结果

运行时间: 220 ms, 内存: 21.0 MB


/*
 * 思路:
 * 使用栈来记录价格和对应的跨度。
 * 对于每个新的价格,栈顶记录前一个价格及其跨度。
 * 如果当前价格大于栈顶价格,则出栈并增加当前价格的跨度,直到栈为空或栈顶价格大于当前价格。
 * 使用流处理来实现遍历操作。
 */

import java.util.Stack;
import java.util.stream.IntStream;

class StockSpanner {
    private Stack<int[]> stack;

    public StockSpanner() {
        stack = new Stack<>();
    }

    public int next(int price) {
        final int[] span = {1};
        // 使用流遍历栈并计算跨度
        IntStream.iterate(stack.size(), i -> i > 0 && stack.get(i - 1)[0] <= price, i -> i - 1)
                  .forEach(i -> {
                      span[0] += stack.pop()[1];
                  });
        stack.push(new int[]{price, span[0]});
        return span[0];
    }
}

解释

方法:

本题解采用栈(后进先出)的数据结构来解决问题。栈中存储每个价格及其跨度的元组。当调用next函数时,函数会检查栈顶的价格是否小于或等于当前价格;如果是,则栈顶元素被弹出,其跨度被加到当前的跨度计数上。这个过程会一直持续,直到栈为空或栈顶价格大于当前价格。此方法有效地'跳过'了那些小于当前价格的所有连续日期,从而快速计算跨度。

时间复杂度:

O(1) 平均时间复杂度

空间复杂度:

O(n)

代码细节讲解

🦆
在实现StockSpanner类时,为何选择使用栈这种数据结构而不是其他如列表或队列?
栈结构被选用是因为它支持快速的后进先出(LIFO)操作,非常适合解决股票价格跨度问题中的逆向查找需求。在计算某一天的价格跨度时,我们需要考虑直到遇到一个更高价格的连续日子。使用栈可以使得在遇到更高的价格时,快速地弹出所有小于等于当前价格的元素,这是队列或普通列表无法高效完成的。队列的先进先出特性和列表的线性访问特点,在这种类型的逆序问题中表现不如栈。
🦆
在next方法中,栈顶元素弹出的条件是`栈顶价格小于等于当前价格`,这是基于什么考虑?
这个条件基于股票价格跨度的定义,即计算从当前日向前连续多少天的价格不超过当前日的价格。如果栈顶的价格小于或等于当前价格,这意味着从栈顶日期到当前日期间的所有价格都无法打断当前价格的跨度计算。因此,可以将这些小于或等于当前价格的日期的跨度累加到当前日期的跨度中,并继续向前寻找,直到找到一个更高的价格。这种方式确保了跨度的正确累计,同时保持算法的高效性。
🦆
算法实现中提到的'跳过'小于当前价格的连续日期,这种方法的效率如何与直接遍历比较?
通过使用栈来'跳过'小于当前价格的连续日期,算法的平均时间复杂度可以达到O(1)。这是因为每个元素最多被压入和弹出栈一次,即使在最坏的情况下,每个元素的操作次数是常数级别的。相比之下,如果使用直接遍历的方法,我们需要从当前日期向前逐一检查,直到找到一个更高的价格或遍历到起始位置。这种方法的时间复杂度为O(n),在数据量大的情况下效率明显低于使用栈的方法。

相关问题