首页 > 试题广场 >

最大值减去最小值小于或等于num的子数组数量

[编程题]最大值减去最小值小于或等于num的子数组数量
  • 热度指数:4643 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定数组 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]中的最小值。


输入描述:
第一行输入两个数 n 和 num,其中 n 表示数组 arr 的长度
第二行输入n个整数X_i,表示数组arr中的每个元素


输出描述:
输出给定数组中满足条件的子数组个数
示例1

输入

5 2 
1 2 3 4 5

输出

12

备注:


自己实现的时候注意使用下标比较还是使用值在比较,不要搞混。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int num = sc.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        int res = getArrayNum(arr, num);
        System.out.println(res);
    }

    //两个结论:1.到j不满足条件,a[i..j-1]满足条件所以a[m..n]都满足条件(i<=m<=n<=j-1)
    //2.a[i..j]不满足条件,则包含它的也都不满足条件(a[l..k],l<=i<=j<=k)
    //用a[i..j-1]代入条件:max(a[i..j])-min(a[i..j])<=num里进行归纳

    public static int getArrayNum(int[] arr, int num) {
        //判空
        if(arr == null || arr.length == 0){
            return 0;
        }
        //拿LinkedList作为双端队列来使用
        LinkedList qmax = new LinkedList();
        LinkedList qmin = new LinkedList();
        //j是不重置的,因为上面两个结论,到j不满足条件时,j是不变的,所以j只会不断地增长
        //j不重置则使用while语句
        int i = 0;
        int j = 0;
        int result = 0;
        //到j不满足条件时,i..j-1所有的子数组都满足条件,但是计数的时候只计算了从i开头的
        //后面剩下的会到它们为开头的时候计算(如i+1),这也是j不重置的原因
        while(i < arr.length){
            while(j < arr.length){
                //为了保证同一个下标只进栈一次,出栈一次,这样时间复杂度才能保证(每个元素O(1),n个元素O(n))
                //如果break,j不变,而qmin.peekLast()正好是上一轮的j,后面i++,所以判断[i+1..j]是否满足条件
                //到j不满足条件,所以[i+1..j]不一定满足条件
                if(qmin.isEmpty() || qmin.peekLast() != j){
                    //双端队列结构
                    while(!qmax.isEmpty() && arr[j] >= arr[qmax.peekLast()]){
                        qmax.pollLast();
                    }
                    qmax.addLast(j);
                    while(!qmin.isEmpty() && arr[j] <= arr[qmin.peekLast()]){
                        qmin.pollLast();
                    }
                    qmin.addLast(j);
                }
                if(arr[qmax.peekFirst()] - arr[qmin.peekFirst()] > num){
                    break;
                }
                j++;
            }
            //以i开头一共j-i个,a[i..i]到a[i..j-1]
            result += (j - i);
            //开头i要自增,应该把队列中的i移除,只可能在最大和最小地方出现,要不就提前被弹出了
            if(qmax.peekFirst() == i){
                qmax.pollFirst();
            }
            if(qmin.peekFirst() == i){
                qmin.pollFirst();
            }
            i++;
        }
        return result;
    }
}
发表于 2020-09-10 16:55:02 回复(0)
import java.util.*;
import java.io.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(new BufferedInputStream(System.in));
        int n=sc.nextInt();
        int num=sc.nextInt();
        int[] arr=new int[n];
        for(int i=0;i<n;i++){
            arr[i]=sc.nextInt();
        }
        
        int[] min=new int[n];
        int[] max=new int[n];
        int minl=0;
        int minr=-1;
        int maxl=0;
        int maxr=-1;
        int i=0;
        int j=0;
        int res=0;
        while(i<n){
            while(j<n){ 
                while(minl<=minr&&arr[min[minr]]>=arr[j]) minr--;
                min[++minr]=j;
                while(maxl<=maxr&&arr[max[maxr]]<=arr[j]) maxr--;
                max[++maxr]=j;
                if(-arr[min[minl]]+arr[max[maxl]]>num){
                    break;
                }
                j++;
            }
            res+=j-i;
            if(max[maxl]==i) maxl++;
            if(min[minl]==i) minl++;
            i++;
        }
        System.out.println(res);
    }
}

发表于 2020-08-30 21:15:05 回复(0)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int num = sc.nextInt();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        int res = getArrayNum(arr, num);
        System.out.println(res);
    }
    
    public static int getArrayNum(int[] arr, int num) {
        if(arr == null || arr.length == 0)
            return 0;
        LinkedList<Integer> qmax = new LinkedList<>();
        LinkedList<Integer> qmin = new LinkedList<>();
        int res = 0;
        int L = 0;
        int R = 0;
        while(L < arr.length) {
            while(R < arr.length) {
                while(!qmax.isEmpty() && arr[qmax.getLast()] <= arr[R])
                    qmax.removeLast();
                qmax.add(R);
                while(!qmin.isEmpty() && arr[qmin.getLast()] >= arr[R])
                    qmin.removeLast();
                qmin.add(R);
                if(arr[qmax.getFirst()] - arr[qmin.getFirst()] > num)
                    break;
                R++;
            }
            res += R - L;
            if(qmax.getFirst() == L)
                qmax.removeFirst();
            if(qmin.getFirst() == L)
                qmin.removeFirst();
            L++;
        }
        return res;
    }
}

发表于 2020-08-19 14:09:01 回复(0)
和滑动窗口那题类似,都是找当前窗口内最大/最小值
import java.util.LinkedList;
import java.util.Scanner;

public class Main {

    public static int getNum(int[] arr, int num) {
        if (arr == null || arr.length == 0) return 0;
        LinkedList<Integer> qmin = new LinkedList<>();
        LinkedList<Integer> qmax = new LinkedList<>();
        int i = 0, j = 0, res = 0;
        while (i < arr.length) {
            // 求以arr[i]为开头,满足条件最长的子序列
            while (j < arr.length) {
                if (qmin.isEmpty() || qmin.peekLast() != j) {
                    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);
                }
                // 当不再满足题意,max(arr[i...j] - min(arr[i...j]) <= num 退出当前循环
                if (arr[qmax.getFirst()] - arr[qmin.getFirst()] > num)
                    break;
                j++;
            }
            // 以arr[i]为第一个元素的子数组,满足条件的j-i个
            res += j - i;
            // 下一次从i+1开始,删除队列里不再框内的元素arr[i]
            if (qmin.peekFirst() == i) qmin.pollFirst();
            if (qmax.peekFirst() == i) qmax.pollFirst();
            i++;
        }
        return res;
    }


    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int num = sc.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        int res = getNum(arr, num);
        System.out.println(res);
    }
}


编辑于 2020-06-14 13:43:31 回复(1)
表示没看过书,暴力解法而已。
import java.util.*;
 
public class Main{
 
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        while(in.hasNext()){
            int n = in.nextInt();
            int num = in.nextInt();
            int[] arr = new int[n];
            for(int i=0;i<n;i++){
                arr[i] = in.nextInt();
            }
            int sum = 0;
            //包含arr[i]且符合条件的的子数组个数
            for(int i=0;i<n;i++){
                sum++;
                int min = arr[i],max = arr[i];
                int j=i;
                while(j<n-1){
                    int next = arr[j+1];
                    if(max < next && next-min <= num){
                        max = next;
                        j++;
                        sum++;
                    }
                    else if(min > next && max-next <= num){
                        min = next;
                        j++;
                        sum++;
                    }
                    else if( min<=next && next<=max && max - min <= num){
                        j++;
                        sum++;
                    }
                    else break;
                }
                
            }
            System.out.println(sum);
        }
    }
}

发表于 2020-01-17 22:29:41 回复(0)