import java.util.Scanner;
import java.util.LinkedList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()) {
int n = in.nextInt();
int num = in.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = in.nextInt();
}
System.out.println(getNum(arr, num));
}
}
public static int getNum(int[] arr, int num) {
if (arr == null || arr.length == 0) {
return 0; // 检查数组是否为空或长度为0
}
LinkedList<Integer> qmin = new LinkedList<>(); // 存储最小值的双端队列
LinkedList<Integer> qmax = new LinkedList<>(); // 存储最大值的双端队列
int i = 0; // 子数组的起始位置
int j = 0; // 子数组的结束位置
int res = 0; // 满足条件的子数组计数
while (i < arr.length) { // 遍历数组
while (j < arr.length) { // 扩展子数组的右边界
//qmin 队列是一个单调递增队列,队列的最后一个元素(peekLast())是队列中最近添加且最大的元素。
while (!qmin.isEmpty() && arr[qmin.peekLast()] >= arr[j]) {
qmin.pollLast(); // 更新最小值队列
}
qmin.addLast(j);
//qmax 队列是一个单调递减队列,队列的最后一个元素(peekLast())是队列中最近添加且最小的元素。
while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[j]) {
qmax.pollLast(); // 更新最大值队列
}
qmax.addLast(j);
if (arr[qmax.getFirst()] - arr[qmin.getFirst()] > num) {
break; // 如果当前子数组不满足条件,则退出内层循环
}
j++; // 扩展右边界
}
if (qmin.peekFirst() == i) {
qmin.pollFirst(); // 移除过期的最小值
}
if (qmax.peekFirst() == i) {
qmax.pollFirst(); // 移除过期的最大值
}
res += j - i; // 对于每一个以 i 开始的位置,从 i 到 j-1 的所有子数组都满足条件
i++; // 移动左边界
}
return res; // 返回满足条件的子数组总数
}
}
这段 Java 代码实现了查找数组中最大值减去最小值小于或等于 num 的所有子数组的数量。下面是代码的逐行解释:
- 检查数组有效性:如果输入的数组为空或长度为零,直接返回0。
- 初始化两个双端队列:qmin 用于维护子数组的最小值,qmax 用于维护子数组的最大值。
- 初始化变量:i 和 j 分别作为子数组的左右边界,res 用于统计满足条件的子数组数量。
- 外层循环:通过变量 i 遍历数组,代表子数组的起始位置。
- 内层循环:通过变量 j 扩展子数组的右边界。使用双端队列更新子数组的最大值和最小值。如果当前子数组的最大值和最小值的差大于 num,则停止内层循环。
- 更新队列:如果队列头部元素是子数组的起始位置,则将其移除。
- 计算子数组数量:将 j - i 加到 res 上,这表示以 i 为起始位置,有 j - i 个子数组满足条件。
- 移动左边界:增加 i,以检查下一个可能的子数组。
- 返回结果:所有满足条件的子数组数量。
通过这种方法,代码有效地计算了所有满足 "最大值减去最小值小于或等于 num" 条件的子数组数量。

京公网安备 11010502036488号