力扣: No.901 股票价格跨度

题目描述

设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。
当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。

例如,如果未来 7 天股票的价格是 [100,80,60,70,60,75,85],那么股票跨度将是 [1,1,1,2,1,4,6] 。

实现 StockSpanner 类:

StockSpanner() 初始化类对象。
int next(int price) 给出今天的股价 price ,返回该股票当日价格的 跨度 。

做题情况

  1. 做出来且思路与标答一致
  2. 做出来但思路较为复杂
  3. 有思路,但时间复杂度较高无法通过 ☑
  4. 没有思路

自己的想法

跨度定义为小于或等于今天价格的最大连续日数,即我们要找到最近大于自己的价格。自己的想法是在进行next函数操作时,记录当前点最近大于自己的价格。当我们在求每个点的最近大于自己的价格时,我们向前遍历,如果上一个点大于当前点,则停止,如果不大于,就直接转到上一个点的最近大于自己的价格,重复判断当前点是否大于那个点,直到找到大于当前点的点为止。
但考虑最差情况,我们在计算当前点时,都有可能遍历到第一个天,即时间复杂度为O(n*n),在本题的规模下有超时的风险。

标答:单调栈

维护一个逐渐递减的栈。如果当前点小于栈顶的元素,则直接入栈;如果当前点大于栈顶的元素,则弹出栈顶的元素并继续比较,直到栈顶的元素小于当前点停止,之后将当前点压入栈中。同时为了统计当前点与最近大于自己的点之间的点数,我们对栈中的所有元素维护一个差值,代表当前点到上一点之间的价格个数。
因此,如果当前点小于栈顶的元素,则差值为1,压入当前点并返回1;如果当前点大于栈顶元素,则进行出栈,并将差值加上出栈元素的差值(相当于将两段合并为一段),最终压入当前点,并返回当前点的差值。
时间复杂度:因为n为调用next函数的次数,每次会引入一个点,每个点最多进行入栈和出栈两次操作,所以时间复杂度为O(n)。

实际代码

class StockSpanner {
public:
    stack<pair<int,int>> sta;
    StockSpanner() 
    {
        sta.push(make_pair(0,0));
    }
    
    int next(int price) 
    {
        if (price<sta.top().first)
        {
            sta.push(make_pair(price,1));
            return 1;
        }
        else 
        {
            pair<int,int> pai=make_pair(price,1);
            while (!sta.empty()&&price>=sta.top().first)
            {
                pai.second+=sta.top().second;
                sta.pop();
            }
            sta.push(pai);
            return pai.second;
        }
    }
};

总结

其实自己想的思路已经蛮接近了,都是不断跳向上一个较大值。不同的是自己是用较小值来过度的,而标答是维护一个栈,将较小值直接删除了,从当前点直接跳向上一个较大值,因此不需要多次重复调用较小值,在O(n)的时间就可以实现。
另外关于栈的时间复杂度自己也应该学习一下,当引用栈时,每次引入一个点,一个点最多进行两次操作,所以O(n)内就可以实现。用指针或者双指针也是这样的情况,之后遇到后可以留意一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值