input:
1
3 6 4 3 2
3
output:
2
本题的解题思路还是从简化整个流程入手,想要得到复杂度为N的算法,显然需要用到滑动窗口,仔细分析一下该题,其实想得到满足条件的连续子数组有以下两个规律:1.当[i,j]满足要求时,[i,j+1]必然满足要求;2.当[i,j]不满足要求时,[i-1,j]和[i,j-1]也同样不满足要求,所以窗口可以一直往前走,不需要回头。
所以大致的逻辑是:以i=0开头,j递增向后寻找满足条件的连续子数组,找到后就不需要再移动j,因为往后走的每个数组都会满足条件;这个时候移动i,如果i不满足条件,那么就不用再移动i,因为上面的规律告诉我们不移动j不可能再出现极差大于给定值的数组。
需要注意的细节是,队列内保存的应该是对应原数组中的序号,以便于我们判断i移动过程中最大最小队列里的值是否应该被移出去,其次我们需要在i开始移动时候增加判定来固定住j,最后就是注意i不能超过j。
代码:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int e_num = Integer.parseInt(scan.nextLine());//测试数
while(e_num>0){
String num[] = scan.nextLine().split(" ");//目标数组
int target = Integer.parseInt(scan.nextLine());//目标数
int total = 0;
LinkedList<Integer> max = new LinkedList<Integer>();//存放最大值的队
LinkedList<Integer> min = new LinkedList<Integer>();//存放最小值的队
int i = 0;//i代表窗口前端
int j = 0;//j代表窗口后端
while(i < num.length){//从以i为首的连续数组开始找
if( !min.isEmpty() && !max.isEmpty() && (i < j) &&(Integer.parseInt(num[max.peekFirst()]))-(Integer.parseInt(num[min.peekFirst()])) > target){
total += num.length - j + 1;
}else{
while(j < num.length){
while(!min.isEmpty() && Integer.parseInt(num[j])<Integer.parseInt(num[min.peekLast()])){
min.pollLast();
}
min.addLast(j);
while(!max.isEmpty() && Integer.parseInt(num[j])>Integer.parseInt(num[max.peekLast()])){
max.pollLast();
}
max.addLast(j);
j ++;
if((Integer.parseInt(num[max.peekFirst()]))-(Integer.parseInt(num[min.peekFirst()])) > target){
total += num.length - j + 1;
break;
}
}
}
if(max.peekFirst() == i){
max.pollFirst();
}
if(min.peekFirst() == i){
min.pollFirst();
}
i ++;
}
System.out.println(total);
e_num --;
}
}
}