给定一个整型数组arr,和一个整数num
某个arr中的子数组sub,如果想达标,必须满足:sub中最大值 – sub中最小值 <= num,
返回arr中达标子数组的数量
题解:
public static int num(int[] arr, int sum) {
if (arr == null || arr.length == 0 || sum < 0) {
return 0;
}
int count = 0;
LinkedList<Integer> maxWindow = new LinkedList<>();
LinkedList<Integer> minWindow = new LinkedList<>();
//[L,R]
int R = 0;
for (int L = 0; L < arr.length; L++) {
//R不回退
while (R < arr.length) {
//维护大端双端队列
while (!maxWindow.isEmpty() && arr[R] >= arr[maxWindow.peekLast()]) {
maxWindow.pollLast();
}
maxWindow.addLast(R);
//维护小端双端队列
while (!minWindow.isEmpty() && arr[R] <= arr[minWindow.peekLast()]) {
minWindow.pollLast();
}
minWindow.addLast(R);
//进行条件判断
if (arr[maxWindow.peekFirst()] - arr[minWindow.peekFirst()] > sum) {
//ATTENTION:这个地方必须退出来计算count,因为有可能出现R已经走到头但是L未走到头的情况,
//at this stitution 写在里面就不会计算count了。
break;
} else {
R++;
}
}
count += R - L;
//将L位置的数字tan'chu'lai
while (!maxWindow.isEmpty() && maxWindow.peekFirst() <= L) {
maxWindow.pollFirst();
}
while (!minWindow.isEmpty() && minWindow.peekFirst() <= L) {
minWindow.pollFirst();
}
}
return count;
}
思路:
刚开始时L,R指向0小标,R一直向后移动,直至不达标停止。
此时 [L , R)之间所有的搭配都达标。但是我计算的是以L为起点,到R结束(不包括R)的达标的个数是R-L个。
------- 即以L为开头的满足条件的子数组最长到R位置(不包括R)。
之后再让L指针向右移动一下到1下标,再计算以1位置为起点的满足条件的子数组最长到哪个地方停止,然后计算以1为头的子数组个数。
-----------------------循环往后直至L到头
注意的一点是:R是不回退的。