LeeCode_739. 每日温度(暴力+栈)

本文解析LeetCode上的每日温度问题,提供两种解决方案:一种是通过改进暴力法降低时间复杂度,另一种是利用栈实现高效求解。文章详细介绍了每种方法的实现思路及代码示例。

一、介绍

1.题目描述

题目链接:https://leetcode-cn.com/problems/daily-temperatures/

请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

2.测试样例

[73,74,75,71,69,72,76,73]
# [1,1,4,2,1,1,0,0]

[30,40,50,60]
# [1,1,1,0]

[73,69,72,74]
# [3,1,1,0]

二、题解

1、暴力

(1)普通暴力🟢(超时)

最容易想到的一个解法就是直接暴力,对每个数字,向后查找最近的大于它的数字,但是这种做法的复杂度将达到n²,超过时限

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temp) {
        int n=temp.size();
        vector<int> ans;
        int i,j;
        // 遍历每个数
        for(i=0;i<n-1;i++){
            for(j=i+1;j<n;j++){
                // 后面的数大于时,加入到答案
                if(temp[j]>temp[i]){
                    ans.push_back(j-i);
                    break;
                }
            }
            // 若没有更大的数,加入答案0
            if(j==n)ans.push_back(0);
        }
        // 最后一个答案必为0
        ans.push_back(0);
        return ans;
    }
};

(2)改进暴力🔴

由于我们要在一个数的后面找到更大的数,可以考虑从后向前遍历。边遍历边记录【离前面最近的】【各个更大的数】。

实现思路:

  1. a数组为传入的温度数据,next数组记录每个温度第一次出现的下标【即更近的下标】【由于温度<=100,数组长度101,初始全为INT_MAX】,t用于在遍历中标更新最小下标。
  2. 当前温度a[i],看next中是否记录了[a[i]+1,100]的温度下标,找到最小的下标更新t
  3. 若t=INT_MAX,说明未找到。反之,则当前下标对应的答案为t-i;
  4. 更新next[a[i]]=i,即a[i]温度对应的更近下标是i。
  5. 重复234步骤

以[73,69,72,74]为例:

  • 从74(下标3)开始遍历,next中无75-100对应的下标,对应ans=0,记录next[74]=3
  • 遇到72(下标2),next中有73-100对应的下标,最近的是next[74]=3,对应ans=3-2=1,记录next[72]=2
  • 遇到69(下标1),next中有70-100对应的下标,最近的是next[72]=2,对应ans=2-1=1,记录next[69]=1
  • 遇到73(下标0),next中有74-100对应的下标,最近的是next[74]=3,对应ans=3-0=3,记录next[73]=0
  • 结束,得到答案[3,1,1,0]

参考链接:https://leetcode-cn.com/problems/daily-temperatures/solution/mei-ri-wen-du-by-leetcode-solution/

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& a) {
        int n=a.size();
        // ans记录答案,next记录该温度的最小下标
        vector<int> ans(n),next(101,INT_MAX);
        // 从后向前遍历
        for(int i=n-1;i>=0;i--){
            // 当前温度为a[i],找到a[i]+1至100的最近下标
            int t=INT_MAX;
            for(int temp=a[i]+1;temp<=100;temp++){
                // 若存在a[i]+1至100的温度,更新最近下标
                t=min(t,next[temp]);
            }
            // 下标存在,记录答案
            if(t!=INT_MAX) ans[i]=t-i;
            // 当前温度的下标为新的最近下标
            next[a[i]]=i;
        }
        return ans;
    }
};

image-20210917131637839

2、栈🟢

另一种想法就是利用栈,推入小的数,遇到大的数时弹出,计算数字下标距离。

这里要注意的是,我们推入栈的应该是下标而不是数字,因为若推入数字,弹出后无法再获得该数字对应的结果。

【错误做法】若推入的是数字,以[73,69,72,74]为例

  • 推入73,69

  • 遇到72后弹出69,记录69对应的结果是1。弹出69,推入72

  • 遇到74,弹出72,对应结果为1。再弹出73,会误以为对应结果是2。

【正确做法】因此我们要采用推入下标的方式。

  • 推入0,1

  • 遇到72后,72>69【即栈顶指向的值】,弹出下标1,记录69对应的结果是下标相减2-1=1。推入下标2

  • 遇到74,74>72,弹出栈顶下标2,记录72对应的结果是下标相减3-2=1。

    • 继续 74>73,弹出栈顶下标0,记录73对应的结果是下标相减3-0=3。
  • 对于栈中剩余元素,全部弹出并设置对应结果为0

  • 得到结果[3,1,1,0]

注意事项:

  • 栈中储存下标而不是数字
  • 原地修改。由于弹出数字的同时就会得到答案,数字不会再被二次使用,因此可以在原vector上更新数值为最终的天数答案
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temp) {
        int n=temp.size();
        stack<int> stk;
        // 推入第一个数的下标
        stk.push(0);
        int t=0;
        for(int i=1;i<n;i++){
            t=stk.top();
            // 当遇到更大的
            while((!stk.empty())&&temp[i]>temp[t]){
                // 弹出,坐标相减=答案,原地更新答案
                temp[t]=i-t;
                stk.pop();
                // 更新t
                if(!stk.empty()) t=stk.top();
            }
            stk.push(i);
        }
        // 栈中剩余元素对应的答案均为0
        while(!stk.empty()){
            temp[stk.top()]=0;
            stk.pop();
        }
        return temp;
    }
};

image-20210917121657225

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值