最大值减去最小值小于等于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..j]中的最小值。

思路:大数组满足小数组也满足:定义两个指针维持一个动态窗口,一个在前一个在后,前指针右滑表示窗口内进数,后指针右滑表示窗口出数。在一个两个维持窗口最大值和最小值的结构。开始时两个指针都指向第一个元素,窗口内是否满足qmax-qmin<=num,若满足,可以计算当前满足的子数组数,那么就是以后指针开头的到前指针位置的子数组数量,这个数量就是前指针-后指针,前指针继续右滑,在判断时候满足,因为判断的是滑动窗口内最大值与最小值的差,如果这个都满足的话,那么其他值的差也肯定满足,当滑到不满足的时候,那么再向右滑也没有意义了,因为再向右滑,最大值与最小值的差只能变大,不能变小了。所以这里应该让后指针右滑,看是否满足,不知满足再让后指针右滑,否则,计算,前指针右滑。知道前后指针都滑完。

import java.util.LinkedList;

public class Main {

    public static void main(String[] args) {
        int[] arr=getRandomArray(30);
        int num=5;
        printArray(arr);
        System.out.println(getNum(arr, num));
    }

    //for test
    public static int[] getRandomArray(int len){
        if (len < 0) {
            return null;
        }

        int[] arr=new int[len];
        for (int i=0;i<len;i++){
            arr[i]= (int) (Math.random()*10);
        }
        return arr;
    }

    //for test
    public static void printArray(int[] arr){
        if (arr != null) {
            for (int i=0;i<arr.length;i++){
                System.out.print(arr[i]+" ");
            }
            System.out.println();
        }
    }

    public static int getNum(int[] arr,int num){
        if (arr == null || arr.length == 0) {
            return 0;
        }

        LinkedList<Integer> qmin=new LinkedList<Integer>();
        LinkedList<Integer> qmax=new LinkedList<Integer>();
        int i=0;
        int j=0;
        int res=0;

        while (i < arr.length) {
            while (j < arr.length) {
                //采用双端队列位置最小值
                while (!qmin.isEmpty() && arr[qmin.peekLast()] >= arr[j]) {
                    qmin.pollLast();
                }
                qmin.addLast(j);
                //维持最大值
                while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[j]) {
                    qmax.pollLast();
                }
                qmax.addLast(j);
                if (arr[qmax.getFirst()] - arr[qmin.getFirst()] > num) {
                    break;
                }
                j++;
            }
            //如果最大值是i位置上的,此时左指针向右划,i位置过期,i++,当然如果最大值或最小值
            //还是i位置上的值,则抛弃。
            if (qmin.peekFirst() == i) {
                qmin.pollFirst();
            }
            if (qmax.peekFirst() == i) {
                qmax.pollFirst();
            }
            //计算以i开头到j位置上的子数组数量,就是j-i
            res += j - i;
            i++;
        }
        return res;
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值