【题解】力扣1438. 绝对差不超过限制的最长连续子数组

1438. 绝对差不超过限制的最长连续子数组

题目来源

1438. 绝对差不超过限制的最长连续子数组

思路

方法一

滑动窗口+有序集合

使用滑动窗口保持符合条件的子数组,记录最长长度。

使用平衡数,统计当前窗口内的最大值和最小值。

  • 使用leftright两个指针,分别指向滑动窗口的左右两边;
  • right主动右移,left被动右移。当滑动窗口内的最大值与最小值之差大于limit时,left被迫向右移动,直到窗口内的最大值和最小值之差小于limit;每次left向右移动时,被移除窗口的数值的次数都要减一。
  • 用一个数res维护滑动窗口的长度的最大值。
class Solution {
    public int longestSubarray(int[] nums, int limit) {
        TreeMap<Integer, Integer> map = new TreeMap<>();
        // 平衡二叉树
        int left = 0, right = 0;
        int res = 0;
        while (right < nums.length) {
            map.put(nums[right], map.getOrDefault(nums[right], 0) + 1);
            // map.put(key, value)
            // map.getOrDefault(value, default),如果有值,就取值,没值,就取默认值(默认值自己设定的
            // map.lastKey(),取最后的Key,就是最大的值
            // map.firstKey(),取最前面的Key,就是最小的值
            while (map.lastKey() - map.firstKey() > limit) {
                // 下面这一行是让nums[left]的value值减一
                map.put(nums[left], map.get(nums[left]) - 1);
                if (map.get(nums[left]) == 0) {
                    map.remove(nums[left]);
                }
                left ++;
            }
            res = Math.max(res, right - left + 1);
            right ++;
        }
        return res;
    }
}

方法二

滑动窗口+单调队列

在方法一中,我们仅需记录当前窗口内的最大值和最小值,因此可以分别用两个单调队列解决问题。

使用一个单调递减的队列maxque来维护窗口内的最大值,使用一个单调递增的队列minque来维护窗口内的最小值。这样只需要计算两个队列的队首之差,就可以判断单前窗口是否满足条件了。

class Solution {
    public int longestSubarray(int[] nums, int limit) {
        int len = nums.length;
        Deque<Integer> maxque = new LinkedList<>();
        Deque<Integer> minque = new LinkedList<>();
        int left = 0, right = 0;
        int res = 0;
        while(right < len){
            // 队列不为空,且队尾元素小于滑动窗口最右边的值时(不是递减队列),弹出队尾元素
            while(!maxque.isEmpty() && maxque.peekLast() < nums[right]){
                maxque.pollLast();
            }
            // 队列不为空,且不是递增队列时,弹出队尾元素
            while(!minque.isEmpty() && minque.peekLast() > nums[right]){
                minque.pollLast();
            }
            maxque.offerLast(nums[right]);
            minque.offerLast(nums[right]);
            // 计算两个单调队列的队首元素之差是否满足条件
            while(!maxque.isEmpty() && !minque.isEmpty() && maxque.peekFirst() - minque.peekFirst() > limit){
                if(nums[left] == maxque.peekFirst()){
                    maxque.pollFirst();
                }
                if(nums[left] == minque.peekFirst()){
                    minque.pollFirst();
                }
                left++;
            }
            // 更新窗口长度
            res = Math.max(res, right-left+1);
            right++;
        }
        return res;
    }
}

参考来源

  1. 力扣官方题解.1438. 绝对差不超过限制的最长连续子数组
posted @ 2021-03-10 22:03  zzzzzy2k  阅读(82)  评论(0编辑  收藏  举报