题干:

解题报告:

我们用两个指针(i,j)分别代表窗口的左边界和右边界,窗口也就是子数组;
用两个双端队列分别维护这个窗口的最大值和最小值;
当窗口扩大时,即j向右扩展时,窗口内的最大值只会越来越大,而最小值只会越来越小(否则就会等于原来的max和min了),此时,如果max-min>num,则j不应该向右扩展了,因为max-min的范围只会越来越大;
这时,应该让窗口缩小,即i向右扩展,这样max可能会减小,min可能会增大(因为原来的max和min可能会失效,即不在窗口内),这样max-min才会有<=num的可能;

另一个题解:

1)最简单的方法,暴力搜索,如何得到全部满足条件的子数组,
          left = 0, res=0;
          1:我们left不变 right++直到right=arr.length结束,每次right++我们都得到left~right的最大值,最小值 符合条件res++;
          2:然后left++ 重复第一步。

2)首先我们不用遍历n*n次,
          当满足条件right++  不满足时left++  这样时间复杂度为n*2;
          原因:当最大值-最小值>k时 我们right++ 如果arr[right]>最大值 或者arr[right]<最小值 差值都是增大的因此在移动right没有意义。
           left++,将子数组缩小,
           如果移除的数字是最大值,那么次大值-最小值 差值缩小;
           如果移除的数字是最小值,那么最大值-次小值 差值缩小;
           如果移除的是其他数字 差值不变;
           这样的时间复杂度变为n*2。

3)以上两种方法在left和right移动的过程中都要不断进行min和max的判断,提高了时间复杂度。

在遍历过程中不断更新qmin和qmax。

其中补充两个关键点:

1)如果nums[i..j]满足条件, nums[k..j]  (i<= k <= j),都满足条件;

2)如果nums[i..j]不满足条件,所有包含 nums[i..j] 的数组都不满足条件;


AC代码:

class Solution
{
public:
    int getNum(vector<int> nums, int target)
    {
        if(nums.empty())
            return 0;
        deque<int> qmin;    //保存窗口内的最小值,递增  front保存最小的元素位置
        deque<int> qmax;    //保存窗口内的最大值,递减  front保存最大的元素位置
        int i = 0, j = 0;   //nums[i..j]表示数组的范围
        int res = 0;        //表示满足条件的子数组数量
        //依次找到以nums[0],nums[1]...nums[N - 1]作为第一元素的子数组中满足条件的数量有多少个,累加
        while(i < nums.size())
        {
            while(j < nums.size())   // j向右拓展,直到不满足条件
            {
                while(!qmin.empty() && nums[qmin.back()] >= nums[j]) // 更新qmin中最小值的index
                    qmin.pop_back();
                qmin.push_back(j);
                while(!qmax.empty() && nums[qmax.back()] <= nums[j]) // 更新qmax中最大值的index
                    qmax.pop_back();
                qmax.push_back(j);
                if(nums[qmax.front()] - nums[qmin.front()] > target) //如果出现不满足条件的,那么包含以nums[i]起始的窗口的所有子数组都不满足条件
                    break;
                j++;
            }
 
            if(qmin.front() == i)  // 如果窗口为 0 ,直接弹出
                qmin.pop_front();
            if(qmax.front() == i)  // 如果窗口为 0 ,直接弹出
                qmax.pop_front();
 
            res += j - i;          //如果nums[i..j]满足条件,则其子数组都满足条件, 一共 (j - i)个子数组
            i++;                   //继续寻找以nums[i]为起始点的子数组
        }
        return res;
    }
 
};