Leetcode. 739 每日温度

题目信息

LeetoCode地址: . - 力扣(LeetCode)

题目理解

题意很好理解,找到比每日温度更高的温度的已过天数的偏移量。如果找不到,则设为0。

最直观的想法是,从每一天开始向后一天一天找,直到找到更高温度的那一天。但是这种做法时间复杂度过高,有太多重复的操作,因此需要找更优的算法。

单调栈写法

容易发现,当遍历到第i天,温度为25度的前提下,如果第i+1天的温度比25度高,则第i天的结果很好计算,即是1. 如果第i+1天的温度没超过2度,则暂时得不到结果,那不如先将第i+1天的温度暂存起来,继续看第i+2天,如果温度继续走低,则继续看后一天。直到某一天温度比前一天高,假设第j天,则我们可以在暂存区里拿出来这一天,将结果求出。类似的,我们可以将暂存区里更之前的温度也拿出来和第j天对比,求出结果,直到暂存区里的温度都比第j天高,此时再将第j天的温度放入暂存区,重复该过程。

这个暂存区的存取总是后放入的先拿出来计算,很显然是栈的操作,所以这种做法就是单调栈做法。

在temperatures数组的长度为l的情况下,

时间复杂度: O(l), 因为我们对每一个温度只会有三种操作,放入栈,拿出栈,或者直接计算偏移量。

额外空间复杂度:O(l),我们需要一个大小为l的栈存放持续走低的温度数据,直到遇到更大的。

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int l = temperatures.length;
        int[] stack = new int[l];
        int stackTopIndex = -1;
        int[] result = new int[l];
        int i = 0;
        while (i < l) {
            if (stackTopIndex == -1) {
                stack[++stackTopIndex] = i++;
            } else {
                if (temperatures[i] <= temperatures[stack[stackTopIndex]]) {
                    stack[++stackTopIndex] = i++;
                } else {
                    result[stack[stackTopIndex]] = i - stack[stackTopIndex];
                    stackTopIndex--;
                }
            }
        }
        return result;
    }
}

动态规划写法

如何能利用之前算过的数据来推导还未计算过的温度的偏移量呢?让我们分析一下。

很显然,最后一天的温度的更高温度偏移量为0,因为后面没有数据了。

倒数第二天的温度如果比最后一天低,则偏移量为1;相反,如果相同或者更高,则可以根据后一天的偏移量, 这里最后一天的偏移量是0,所以倒数第二天的偏移量也是0;

...

倒数第n天,类似的,先看n+1天,如果温度更高了,则偏移量为1; 相反,则看n+1天的偏移量之后的温度,更高了,则偏移量(n) = 1 + 偏移量(n+1);如果温度还是不够高,则继续看其偏移量,直到满足条件,或者到达最后一天。

这种根据已有的结果计算其他数据的思想就是动态规划。

在temperatures数组的长度为l的情况下,

时间复杂度: O(l), 看似我们有循环操作,但是它们搜索的数据空间没有重复,因此时间复杂度是O(l).

额外空间复杂度:O(1), 除了存放结果的集合,不需要其他额外的空间。

class Solution {
public int[] dailyTemperatures(int[] temperatures) {
        int[] dp = new int[temperatures.length];
        dp[temperatures.length-1] = 0;
        for (int i = temperatures.length-2; i>=0;i--) {
            if (temperatures[i] < temperatures[i+1]) {
                dp[i] = 1;
            } else {
                int j = i+1;
                while (j < dp.length && temperatures[j] <= temperatures[i]) {
                    if (dp[j] == 0) {
                        break;
                    }
                    j = j + dp[j];
                }
                if (j < dp.length && temperatures[j] > temperatures[i]) {
                    dp[i] = j-i; 
                }
            
            }
        }
        return dp;
    }
}

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值