package algorithm;

import java.util.LinkedList;

/**
 * 程序员代码代码面试指南:最大值减去最小值小于或者等于num的子数组数量
 * 1.变量
 * qmax:LinkedList<Integer>,用来实现子数组的最大值,队头为当前子数组的最大值
 * qmin:LinkedList<Integer>,用来实现子数组的最小值,队头为当前子数组的最小值
 * result:int,统计符合条件的子数组数量
 * 2.对输入进行校验
 * arr不为空,且长度大于0
 * 3.双重遍历
 * i,j为arr数组下标,i=0,j=i
 * j向右移动,到数组尽头完成一次遍历,j++,j<arr.length
 * i向右移动,i++,j再进行一次遍历
 * i移动到数组尽头,遍历结束,i<arr.length
 * 4.数组下标入队
 * 入队的下标为j
 * j进入qmax之前先进行循环判断,如果队尾元素小于或者等于arr[j],则要先弹出,直到没有比他小的元素再入队:!qmax.isEmpty()&&qmax.peekLast()<=arr[j]
 * j进入qmin之前先 进行循环判断,如果队尾元素大于或者等于arr[j],则要先弹出,直到没有比他大的元素再入队:!qmin.isEmpty()&&qmin.peekLast()>=arr[j]
 * 5.统计符合条件的子数组数量
 * 判断qmax和qmin的队头元素是否满足条件,满足则result++:qmax.peekFirst() - qmin.peekFirst() <= num
 * 6.清除无效下标
 * 如果队头元素不在范围就出队:qmax.peekFirst() < i || qmax.peekFirst() > j,qmin.peekFirst() < i || qmin.peekFirst() > j
 */
public class SubarrayNum {
    /**
     * 最大值减去最小值小于或者等于num的子数组数量
     * @param arr 原数组
     * @param num 要比较的值
     * @return 符合条件的字数组数量
     */
    public static int getNum(int[] arr, int num) {
        LinkedList<Integer> qmax = new LinkedList<>();
        LinkedList<Integer> qmin = new LinkedList<>();
        int result = 0;
        if (arr.length == 0 || arr == null) {
            return 0;
        }
        for (int i = 0; i < arr.length; i++) {
            for (int j = i; j < arr.length; j++) {
                while (!qmax.isEmpty() && qmax.peekLast() <= arr[j]) {
                    qmax.pollLast();
                }
                qmax.addLast(j);
                while (!qmin.isEmpty() && qmin.peekLast() >= arr[j]) {
                    qmin.pollLast();
                }
                qmin.addLast(j);
                if (qmax.peekFirst() - qmin.peekFirst() <= num) {
                    result++;
                }
                if (qmax.peekFirst() < i || qmax.peekFirst() > j) {
                    qmax.pollFirst();
                }
                if (qmin.peekFirst() < i || qmin.peekFirst() > j) {
                    qmin.pollFirst();
                }
            }
        }
        return result;
    }

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        int[] arr = {3, 5, 7, 8, 6, 2};
        System.out.println(getNum(arr, 5));
    }
}