Loading

[LeetCode] 739. Daily Temperatures(每日温度)

Description

Given a list of daily temperatures T, return a list such that, for each day in the input, tells you how many days you would have to wait until a warmer temperature. If there is no future day for which this is possible, put 0 instead.
给定一个每日温度列表 T,返回一个列表,对于每一天的温度,能告诉你到下一个更温暖的温度还需等多少天。如果等不到这一天,则返回 0

For example, given the list of temperatures T = [73, 74, 75, 71, 69, 72, 76, 73], your output should be [1, 1, 4, 2, 1, 1, 0, 0].
例如,给定输入 T = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]

Note

The length of temperatures will be in the range [1, 30000]. Each temperature will be an integer in the range [30, 100].
temperature 的长度在 [1, 300000]。每一天的温度的范围在 [30, 100]。(译者注:这一定不是在地球上的温度,或者用的是华氏温标?🌚)

Hints

  1. If the temperature is say, 70 today, then in the future a warmer temperature must be either 71, 72, 73, ..., 99, or 100. We would remember when all of them occur next.
    如果今日的温度是 70,那么未来几日,更温暖的温度一定是从 71 到 100。我们可以在其下一次出现的时候记录下来。

Solution

这题一给出来,我的第一想法是“单调栈”这个数据结构。不过单调栈 Emmmm……我不会呀,遂求助于 Bing,查找的结果证明我的直觉是正确的。以下为单调栈的相关资料(摘抄于特殊数据结构:单调栈 - labuladong 的算法小抄

单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)。

听起来有点像堆(heap)?不是的,单调栈用途不太广泛,只处理一种典型的问题,叫做 Next Greater Element

…………

给你一个数组,返回一个等长的数组,对应索引存储着下一个更大元素,如果没有更大的元素,就存 -1。

…………

这个问题可以这样抽象思考:把数组的元素想象成并列站立的人,元素大小想象成人的身高。这些人面对你站成一列,如何求元素「2」的 Next Greater Number 呢?很简单,如果能够看到元素「2」,那么他后面可见的第一个人就是「2」的 Next Greater Number,因为比「2」小的元素身高不够,都被「2」挡住了,第一个露出来的就是答案。)

这个情景很好理解吧?带着这个抽象的情景,先来看下代码。

vector<int> nextGreaterElement(vector<int>& nums) {
    vector<int> res(nums.size()); // 存放答案的数组
    stack<int> s;
    // 倒着往栈里放
    for (int i = nums.size() - 1; i >= 0; i--) {
        // 判定个子高矮
        while (!s.empty() && s.top() <= nums[i]) {
            // 矮个起开,反正也被挡着了。。。
            s.pop();
        }
        // nums[i] 身后的 next great number
        res[i] = s.empty() ? -1 : s.top();
        // 
        s.push(nums[i]);
    }
    return res;
}

这就是单调队列解决问题的模板。for 循环要从后往前扫描元素,因为我们借助的是栈的结构,倒着入栈,其实是正着出栈。while 循环是把两个「个子高」元素之间的元素排除,因为他们的存在没有意义,前面挡着个「更高」的元素,所以他们不可能被作为后续进来的元素的 Next Great Number 了。

对单调栈的介绍到此为止。回到这个问题本身,上面的资料中本身已经给了单调栈的模板代码了,大部分都能直接套用进去。有两点需要变动一下:

  1. 单调栈里存放的是元素的下标值而非元素本身。

  2. 最后的结果里存的不是元素下标,而是两元素下标间的差值。

最后得到的代码如下:

import java.util.*

class Solution {
    fun dailyTemperatures(T: IntArray): IntArray {
        val stack = ArrayDeque<Int>()
        val result = IntArray(T.size)

        for (i in T.indices.reversed()) {
            while (stack.isNotEmpty() && T[stack.peek()] <= T[i]) {
                stack.pop()
            }
            result[i] = if (stack.isEmpty()) 0 else stack.peek() - i
            stack.push(i)
        }

        return result
    }
}

参考文献

  1. labudadong, 特殊数据结构:单调栈, https://labuladong.gitbook.io/algo/shu-ju-jie-gou-xi-lie/dan-tiao-zhan#wen-ti-bian-xing
posted @ 2020-10-27 09:52  Zhongju.copy()  阅读(140)  评论(0编辑  收藏  举报