【队列】最大值减去最小值小于等于num的子数组数量

摘自《程序员代码面试指南》

题目:

给定数组 arr 和整数 num, 共返回有多少个?数组满?如下情况:
max(arr[i...j]) - min(arr[i...j]) <= num
max(arr[i...j])表示?数组 arr[i...j]中的最?值,min(arr[i...j])表示?数组arr[i...j]中的最小值。

题解:

  区间最大最小值,立刻联想到单调栈(双端队列),不过稍微麻烦一些,需要在此基础上总结一些规律。

  如果?数组 arr[i..j]满?条件, 即 max(arr[í.._i])-min(arr[i..j])<=num, 那么 arr[i..j]中的每?个?数组, 即 arr[k..l](i<=k<=|<=j)都满?条件 我们以?数组 arr[i..j-1]为例说明, arr[i..j-1]最?值只可能?于或等于arr[i..j]的最大值, arr[i..j-1]最小值只可能大于或等于 arr[i..j]的最小值, 所以 arr[i..j-|]必然满?条件, 同理, arr[i..j]中的每?个?数组都满?条件  

  如果?数组 arr[i..j]不 满?条件, 那 么 所有 包含 arr[i..j]的 ?数组, 即arr[k..l](k<=i<=j<=|)都不满?条件. 证明 过程同 第 ?个结论

  也就是说,此问题还满足一个性质,那就是可以根据两端的下标范围确定满足条件的子数组个数,这一点很重要

Solution

#include <iostream>
#include <vector>
#include <deque>

using namespace std;

int maxMatchedArray(vector<int> &nums, int num){
    deque<int> qmax, qmin;
    int n = nums.size();
    int res = 0;
    int i = 0, j = 0;
    while (i < n){
        while (j < n){
            while (!qmin.empty() && nums[qmin.back()] >= nums[j])
                qmin.pop_back();
            qmin.push_back(j);
            while (!qmax.empty() && nums[qmax.back()] <= nums[j])
                qmax.pop_back();
            qmax.push_back(j);
            if (nums[qmax.front()] - nums[qmin.front()] > num)
                break;
            ++j;
        }
        if (qmin.front() == i)
            qmin.pop_front();
        if (qmax.front() == i)
            qmax.pop_front();
        res += j - i; //所有以arr[i]作为第一个元素的子数组,满足条件的数量为 j - i 个
        ++i;
    }
    return res;
}

int main(){
    vector<int> v{ 8,7,12,5,16,9,17,2,4,6};
    int n = 3;
    cout << maxMatchedArray(v, n) << endl;
    system("pause");
    return 0;
}
时间: 2024-10-06 15:52:38

【队列】最大值减去最小值小于等于num的子数组数量的相关文章

栈和队列----最大值减去最小值小于等于num的子数组的数量

最大值减去最小值小于等于num的子数组的数量 给定数组arr和整数 num,共返回有多少个数组满足下列情况: max(arr[i..j])-min(arr[i..j])<=num.其中max(arr[i..j]) 表示子数组arr[i..j] 中的最大值,min(arr[i..j]) 表示子数组arr[i..j] 中的最小值.如果数组的长度为N,要求时间复杂度是 O(N). [解析] 使用双端队列,qmax维护着窗口子数组arr[i..j]的最大值更新的结构,qmin维护着窗口子数组arr[i.

最大值减去最小值小于或等于num的子数组数量

[说明]: 本文是左程云老师所著的<程序员面试代码指南>第一章中“最大值减去最小值小于或等于num的子数组数量”这一题目的C++复现. 本文只包含问题描述.C++代码的实现以及简单的思路,不包含解析说明,具体的问题解析请参考原书. 感谢左程云老师的支持. [题目]: 给定数组 arr 和整数 num,共返回多少个字数组满足如下情况: max(arr[i...j]) - min(arr[i...j]) <= num max(arr[i...j]) 表示字数组 arr[i...j] 中的最大

[程序员代码面试指南]栈和队列-最大值减去最小值 小于或等于num 的子数组的数量(双端队列)

题目 给定数组arr和整数num,求数组的子数组中有多少个的满足"最大值减去最小值<=num". 解题思路 分析题目,有结论: 如果数组arr[i...j]满足条件,则它的每一个子数组都满足条件. 如果数组arr[i...j]不满足条件,则包含它的每一个数组都不满足条件. 数据结构:用i.j表示当前窗口,分别使用两个双端队列维护窗口的最大值和最小值. 具体地,每次更新两个双端队列,检查当前的窗口是否满足条件,满足则j++,不满足则cnt+=j-i,更新双端队列,i++,j不变.若

左神算法书籍《程序员代码面试指南》——1_10最大值减去最小值小于或等于num的子数组数量

[题目]给定数组arr和整数num,共返回有多少个子数组满足如下情况:max(arr[i.j]) - min(arr[i.j]) <= num max(arfi.j])表示子数组ar[ij]中的最大值,min(arli.j])表示子数组arr[i.j]中的最小值.[要求]如果数组长度为N,请实现时间复杂度为O(N)的解法.[题解]使用两个单调栈,一个栈维持从大到小的排序,头部永远是最大值一个维持从小到大的排序,头部永远都是最小值然后使用窗口进行数据移动当右移后,最大最小差超过num时,计算这段数

1.10 最大值减去最小值小于或等于num的子数组数量

[题目]: 给定数组arr和整数num,共返回有多少个子数组满足如下情况: max(arr[i...j] - min(arr[i...j]) <= num max(arr[i...j])表示子数组arr[i...j]中的最大值,min(arr[i...j])表示子数组arr[i...j]中的最小值 [要求]: 如果数组长度为N,请实现时间复杂度为O(N)的解法 原文地址:https://www.cnblogs.com/latup/p/9908350.html

算法总结之 最大值减去最小值或等于num的子数组数量

给定数组arr和整数num,共返回有多少个子数组满足  <= num 数组长度N    时间复杂度O(N) package TT; import java.util.LinkedList; public class Test127 { public int getNum(int[] arr, int num){ if(arr==null || arr.length == 0){ return 0; } LinkedList<Integer> qmin = new LinkedList&l

求数组所有区间最大值减去最小值之差的和(贝壳笔试题)

这个题直接暴力求解的话时间复杂度肯定是不行的,所以,我们要计算每个数值的贡献,对每一个数求他当最小值当了多少次,当最大值当了多少次,最后当最大值的次数乘以这个数值减去当最小值的次数乘以数值就得到这个数的贡献,依次把这n个数的贡献加起来就是整个极差之和. 在计算一个数当了多少最值的时候,我们要理解问题,因为区间是连续的,所以,以最小值为例,如果一个数是当前这段区间的最小值,那么他一定是当前这段区间最小的(这不废话),所以,我们就找到他往左做多能找到多少个连续的数都比他大,记录这个位置,同理找他右边

POJ 3264 Balanced Lineup【线段树区间查询求最大值和最小值】

Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 53703   Accepted: 25237 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer Joh

二维数组求子数组之和最大值(首尾相接, 圆柱)

问题:求二维数组的子数组之和的最大值(首尾相接,即形成圆柱) 成员: 陈晨:负责代码复审和代码测试计划 王颖瑞:负责程序分析,代码编程 思路:对于这个问题,我们可以结合之前的实验(二维数组求子数组之和的最大值和首尾相连一维数组的子数组之和的最大值),把为二维数组的列扩大二倍,之后想一维数组(首尾相连)一样,把二维数组分成不同的几个二维数组.之后就分开求不同的二维数组的子数组的最大值,最后之间比较,求出总的最大值. 代码: #include<iostream> using namespace s