单调栈-leetcode-739. 每日温度

单调栈-leetcode-739. 每日温度,第1张

739. 每日温度

题目描述

暴力
class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int n = temperatures.length;
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (temperatures[j] > temperatures[i]) {
                    res[i] = j - i;
                    break;
                }
            }
        }
        return res;
    }
}
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 时间复杂度: O ( 1 ) O(1) O(1) (忽略res数组)
单调栈

在求数组/队列中 左边(或右边)下一个最大值(或最小值)时,使用单调栈是一个非常不错的解法。


复杂版

由于本题目是求数组中“右边第一个比当前元素大”的节点,所以这里采用的单调栈为:

  • 从栈顶到栈低 --> nums[index]单调递增;
  • 栈中存的是temperatures下标i

思路:

  1. 遍历 t e m p e r a t u r e s temperatures temperatures 中所有元素,设当前下标为 i i i
  2. 若当前stack为空,则直接将 i i i入栈,就完事了;
  3. 否则,若以当前栈顶元素(由于栈中存放的是下标,其实是 t e m p e r a t u r e s [ s t a c k . p e e k ( ) ] temperatures[stack.peek()] temperatures[stack.peek()]<= 当前元素 t e m p e r a t u r e s [ i ] temperatures[i] temperatures[i],则不会破坏单调性,直接将 i 入栈,即可;
  4. 否则,若栈顶元素(同3解释) > 当前元素 t e m p e r a t u r e s [ i ] temperatures[i] temperatures[i],此时“单调性”被破坏,需要d栈维护“单调性”;
    • 若当前栈非空,且 temperatures[i] > temperatures[stack.peek(),则需要d栈;
    • 此时(单调性失效),当前元素 t e m p e r a t u r e s [ i ] temperatures[i] temperatures[i] 是栈中所有使得“单调性失效”元素的 右边第一个比它大的节点,则需要在d栈时在 r e s res res 中记录之,即 res[index] = i - index;

两点注意

  1. 栈中存放的是下标 i i i,比较时应该是 t e m p e r a t u r e s [ i ] < = t e m p e r a t u r e s [ t o p ] temperatures[i] <= temperatures[top] temperatures[i]<=temperatures[top],而不是 t e m p e r a t u r e s [ i ] < = t o p temperatures[i] <= top temperatures[i]<=top
  2. 在d栈维护单调性时(while循环中),循环条件必须为 temperatures[i] > temperatures[stack.peek()],而不是 temperatures[i] > temperatures[top]

    此时,d栈后栈顶元素是动态变化的!!!

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        if (temperatures.length < 1) return new int[]{};
        int[] res = new int[temperatures.length];
        // 从栈顶到栈低 --> nums[index]单调递增
        // 栈中存的是temperatures下标i
        Deque<Integer> stack = new LinkedList<>();
        for (int i = 0; i < temperatures.length; i++) {
            if (stack.isEmpty()) {
                stack.push(i);
                continue;
            }
            int top = stack.peek();
            // 仍然(非严格)单调增,直接入栈
            if (temperatures[i] <= temperatures[top]) { // 注意:不是 <= top
                stack.push(i);
            } else { // >
                while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) { // 不能temperatures[i] > top
                    int index= stack.pop();
                    // 记录
                    res[index] = i - index;
                }
                // 当前元素下标入栈
                stack.push(i);
            }
        }
        return res;
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 时间复杂度: O ( n ) O(n) O(n) (忽略res数组)

可见单调栈其实是“用空间换时间”!

精简版

以上代码存在冗余部分,可精简如下:

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        if (temperatures.length < 1) return new int[]{};
        int[] res = new int[temperatures.length];
        // 单调栈:从栈顶到栈低 --> nums[index]单调递增,栈中存的是temperatures下标i
        Deque<Integer> stack = new LinkedList<>();
        for (int i = 0; i < temperatures.length; i++) {
            while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) { // 不能temperatures[i] > top
                int index = stack.pop();
                res[index] = i - index;  // 记录
            }
            // 当前元素入栈
            stack.push(i); 
        }
        return res;
    }
}

时、空复杂度不变。


1019. 链表中的下一个更大节点

题目描述

单调栈

思路:

  • 将链表转化为数组;
  • 然后,同739. 每日温度一样了
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public int[] nextLargerNodes(ListNode head) {
        // 将链表转化为数组
        List<Integer> nums = new ArrayList<>();
        while (head != null) {
            nums.add(head.val);
            head = head.next;
        }
        System.out.println(nums);
        int n = nums.size();
        int[] res = new int[n];
        // 单调栈:从栈顶到栈低递增(非严格),栈中存放的是nums的下标
        Deque<Integer> stack = new LinkedList<>();
        for (int i = 0; i < n; i++) {
            if (stack.isEmpty()) {
                stack.push(i);
                continue;
            }
            if (nums.get(i) <= nums.get(stack.peek())) {
                stack.push(i);
            } else {
                // 维护单调性(其中,栈中存放的是nums的下标)
                while (!stack.isEmpty() && nums.get(stack.peek()) < nums.get(i)) {
                    System.out.println("--------------");
                    System.out.println("stack = " + stack);
                    // d栈并记录
                    int index = stack.poll();
                    // 当前元素是单调栈中需要d栈单调性的节点的右边第一个更大值
                    res[index] = nums.get(i);
                    System.out.println("i = " + i);
                    System.out.println("index = " + index);
                }
                // 当前元素入栈(保证单调增)
                stack.push(i);
            }
        }
        return res;
    }
}

参考:

  • 单调栈详解
  • Carl题解

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563158.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存