数据结构--最大值减去最小值小于或等于num的子数组数量

给定数组arr和整数num, 共返回有多少个子数组满足如下情况:
max(arr[i..j]) - min(arr[i..j]) <= num
max(arr[i..j])表示子数组arr[i..j]中的最大值, min(arr[i..j])表示子数组arr[i.中的最小值。
【要求】
如果数组长度为N, 请实现时间复杂度为O(N)的解法。

子数组要求其中的元素是连续

解法一:暴力法  O(N³)  不可取

通过循环,找遍数组中所有的子数组,同时判断子数组中的值是否满足条件,如果满足,则加入到结果中

解法二:

①、如果一个子数组从L->R中,arr[max] - arr[min] <= num,那么在L->R范围内的子数组都符合要求

②、如果一个子数组从L->R中,arr[max] - arr[min] > num,那么以L->R为基础向外扩的子数组都不符合要求

做两个双端队列,一个是窗口内最大值,另外一个是窗口内最小值

1)、开始时L在数组最左端 0 位置,R从最左端开始向右扩,直到再扩充一个值就不符合要求时,R停止,设此时为 x 位置

则以0位置开始的子数组有 x + 1个(0,0~1,……0~x)  这些子数组是以0为起始位置符合要求的所有子数组个数

2)、L向右边移动一个位置,更新两个窗口内的结构,然后R试着继续向右扩,重复上面的,然后就能得到以1为起始位置符合要求的所有子数组个数

L每次向右移动一个位置,R就开始向右扩

/**
 * Created by Skye on 2018/5/3.
 * 给定数组arr和整数num, 共返回有多少个子数组满足如下情况:
 max(arr[i..j]) - min(arr[i..j]) <= num
 max(arr[i..j])表示子数组arr[i..j]中的最大值, min(arr[i..j])表示子数组arr[i.中的最小值。
 【要求】
 如果数组长度为N, 请实现时间复杂度为O(N)的解法。


 从当前位置 i 开始 采用双重循环, j 向后面开始扩充,采用两个队列,分别记录当前 i - j 的最大值和最小值
 当 arrays[maxList.peekLast()] - arrays[minList.peekLast()] > num 时不满足题意,
 则 j 停止扩充,然后计算从 i 到 j 共有多少个子数组  j - i 记录,
 并且判断当前位置 i 是否还在最大或最小队列中,如果存在,则弹出,因为 i 马上要过期了
 然后 i++ 继续扩充
 */
public class AllLessNumSubArray {

    public static int lessNumArray(int[] arrays, int num){
        if(arrays == null || arrays.length == 0) return 0;
        LinkedList<Integer> maxList = new LinkedList<>();
        LinkedList<Integer> minList = new LinkedList<>();
        int res = 0;
        int i = 0;
        int j = 0;
        while(i < arrays.length){
            while(j < arrays.length){
                while(!maxList.isEmpty() && arrays[maxList.peekLast()] <= arrays[j]){
                    maxList.pollLast();
                }
                while(!minList.isEmpty() && arrays[minList.peekLast()] >= arrays[j]){
                    minList.pollLast();
                }
                maxList.addLast(arrays[j]);
                minList.addLast(arrays[j]);
                j++;
                if(arrays[maxList.peekLast()] - arrays[minList.peekLast()] > num){
                    break;
                }
            }
            //判断是否超过了边值条件
            if(maxList.peekFirst() == i) maxList.pollFirst();
            if(minList.peekFirst() == i) minList.pollFirst();
            res += j - i;
            i++;
        }
        return res;
    }
}

  

原文地址:https://www.cnblogs.com/SkyeAngel/p/8985801.html