Loading

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

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

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

《程序员代码面试指南》第10题 P31 难度:校★★★☆

本题刚开始理解错误,导致想了一个小时没想出来。没想到题目的意思是子数组是连续的(arr[i..j]代表连续的意思。。醉了)

这题也算是生成窗口最大值数组问题的进阶版,核心思路还是用滑动窗口,只不过一个维护窗口子数组的最大值另一个维护其最小值

根据2个前提条件

  1. 如果子数组arr[i..j]满足条件,则arr[i..j]的每一个子数组也都满足条件
  2. 如果子数组arr[i..j]不满足条件,则包含arr[i..j]的子数组都不满足条件

可以得到整个过程如下:

  1. 生成两个双端队列qmaxqmin,两个整型变量ij,整型变量res(用来表示所有满足的子数组数量
  2. j不断++,即窗口右扩qmax和qmin不断更新(更新规则见生成窗口最大值数组),直到子数组不满足条件,则停止右扩。此时其中以arr[i]为首的所有子数组都满足条件res+=j-i
  3. i向右移动一个位置再次执行步骤2,即求其中以arr[i+1]为首的所有满足条件的子数组的数量
  4. 步骤2和3循环直到结束,最后求出以arr[0]、arr[1]、arr[2]……为首的所有满足条件的子数组的数量的总和即为答案

牛客题解代码如下:

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);
    }
}
posted @ 2021-11-05 14:11  幻梦翱翔  阅读(56)  评论(0)    收藏  举报