zoukankan      html  css  js  c++  java
  • 滑动窗口-BST-单调队列-1438. 绝对差不超过限制的最长连续子数组

    2020-05-05 17:00:57

    问题描述:

    给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。

    如果不存在满足条件的子数组,则返回 0 。

    示例 1:

    输入:nums = [8,2,4,7], limit = 4
    输出:2
    解释:所有子数组如下:
    [8] 最大绝对差 |8-8| = 0 <= 4.
    [8,2] 最大绝对差 |8-2| = 6 > 4.
    [8,2,4] 最大绝对差 |8-2| = 6 > 4.
    [8,2,4,7] 最大绝对差 |8-2| = 6 > 4.
    [2] 最大绝对差 |2-2| = 0 <= 4.
    [2,4] 最大绝对差 |2-4| = 2 <= 4.
    [2,4,7] 最大绝对差 |2-7| = 5 > 4.
    [4] 最大绝对差 |4-4| = 0 <= 4.
    [4,7] 最大绝对差 |4-7| = 3 <= 4.
    [7] 最大绝对差 |7-7| = 0 <= 4.
    因此,满足题意的最长子数组的长度为 2 。
    示例 2:

    输入:nums = [10,1,2,4,7,2], limit = 5
    输出:4
    解释:满足题意的最长子数组是 [2,4,7,2],其最大绝对差 |2-7| = 5 <= 5 。
    示例 3:

    输入:nums = [4,2,2,2,4,4,2,2], limit = 0
    输出:3

    提示:

    1 <= nums.length <= 10^5
    1 <= nums[i] <= 10^9
    0 <= limit <= 10^9

    问题求解:

    解法一:BST

    最经典的滑动窗口解法:

    • 每次追加一个数
    • 收缩左端点使之有效

    这里有个核心的地方就是维护了一个循环不变量,即每次得到的都是以右端点结尾的最长的子数组,并且从这个合法的子数组扩展得到的才有可能是合法的。

    本题中如果是一个不合法的子数组追加元素的话,由于最大值不能变小,最小值不可能变大,所以无论追加什么数字,总归是不合法的。

    那么现在核心的问题就是如何得到一个窗口内的极值了,容易想到的是使用BST来得到。

    时间复杂度:O(nlogn)

        public int longestSubarray(int[] nums, int limit) {
            int res = 0;
            int n = nums.length;
            TreeMap<Integer, Integer> map = new TreeMap<>();
            int l = 0;
            for (int r = 0; r < n; r++) {
                map.put(nums[r], map.getOrDefault(nums[r], 0) + 1);
                while (map.lastKey() - map.firstKey() > limit) {
                    map.put(nums[l], map.get(nums[l]) - 1);
                    if (map.get(nums[l]) == 0) map.remove(nums[l]);
                    l++;
                }
                res = Math.max(res, r - l + 1);
            }
            return res;
        }
    

      

    解法二:单调队列

    另一种思路就是使用单调队列去得到窗口中的极值。

    时间复杂度:O(n)

        public int longestSubarray(int[] nums, int limit) {
            int res = 0;
            int n = nums.length;
            Deque<Integer> q_max = new LinkedList<>();
            Deque<Integer> q_min = new LinkedList<>();
            int l = 0;
            for (int r = 0; r < n; r++) {
                while (!q_max.isEmpty() && q_max.getLast() < nums[r]) q_max.pollLast();
                while (!q_min.isEmpty() && q_min.getLast() > nums[r]) q_min.pollLast();
                q_max.addLast(nums[r]);
                q_min.addLast(nums[r]);
                while (q_max.getFirst() - q_min.getFirst() > limit) {
                    if (q_max.getFirst() == nums[l]) q_max.pollFirst();
                    if (q_min.getFirst() == nums[l]) q_min.pollFirst();
                    l++;
                }
                res = Math.max(res, r - l + 1);
            }
            return res;
        }
    

      

  • 相关阅读:
    基本算法2
    基本算法
    读书笔记 《跟老齐学python》
    python杂记 20200207 离线安装 正则
    傻傻分不清之 Cookie、Session、Token、JWT 转载:https://juejin.im/post/5e055d9ef265da33997a42cc
    并发相关 杂记
    原根
    POJ2749 Building roads
    luogu P4735 最大异或和
    SP913 QTREE2
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/12831442.html
Copyright © 2011-2022 走看看