最大值和最小值之差达标的子数组数量
创始人
2024-04-07 22:20:57
0

1、题目

给定一个整型数组 arr,和一个整数 num

某个 arr 中的子数组 sub,如果想达标,必须满足:sub中最大值 - sub中最小值 <= num。

请返回 arr 中达标子数组的数量。

2、思路

结论1:如果 [L...R] 范围上的 max - min <= sum,则 L...R 范围上的所有子数组都是达标的。

解释:假设 [L'...R'][L...R] 的子数组
[L...R]max - [L...R]min <= sum
[L'...R']max' <= [L...R]max[L'...R']min >= [L...R]min
因此:[L'...R']max' - [L'...R']min <= sum,依然是达标的。

结论2:如果 [L...R] 范围上的 max - min > sum,那么无论 L 往左扩还是 R 往右扩,产生的新的子数组一定是不达标的。

思路:准备一个最大值更新结构qmax 和一个最小值更新结构 qmin,用于维护最大值和最小值。

假设窗口一开始为0,此时 L = 0,让 R 往右扩,每扩一次就更新 qmaxqmin,如果达标就继续扩,一直到位置 ppp 不达标了,那么必须以 0 位置开始的子数组达标的数量一共有 p−0+1=p+1p - 0 + 1 = p + 1p−0+1=p+1 个。

然后 L 往右滑动到1,即 L = 1 时,R 继续往右扩,看是否达标,直到到达不能达标的位置,则能得到必须以 1 位置开始的子数组的达标数量。

注意:该过程中 LR 都没有回退,一共只会滑过 n 个数,所以时间复杂度是 O(n)O(n)O(n)。

  • C++ 版
/*************************************************************************> File Name: 002.最大值和最小值差达标的子数组数量.cpp> Author: Maureen > Created Time: 四 11/10 18:06:16 2022************************************************************************/#include 
#include 
#include 
using namespace std;//暴力对数器 O(n^3)
int right(vector &arr, int sum) {if (arr.size() == 0 || sum < 0) {return 0;}int n = arr.size();int count = 0;for (int l = 0; l < n; l++) {for (int r = l; r < n; r++) {int maxV = arr[l];int minV = arr[l];for (int i = l + 1; i <= r; i++) {maxV = max(maxV, arr[i]);minV = min(minV, arr[i]);}if (maxV - minV <= sum)count++;}}return count;
}//滑动窗口 O(n)
int way(vector &arr, int sum) {if (arr.size() == 0 || sum < 0) {return 0;}deque qmax; //最大值的更新结构deque qmin; //最小值的更新结构int n = arr.size();int count = 0;int r = 0;for (int l = 0; l < n; l++) { //枚举子数组的开始位置lwhile (r < n) {//最大值的更新while (!qmax.empty() && arr[qmax.back()] <= arr[r]) {qmax.pop_back();}qmax.push_back(r);//最小值的更新while (!qmin.empty() && arr[qmin.back()] >= arr[r]) {qmin.pop_back();}qmin.push_back(r);//该子数组是否达标if (arr[qmax.front()] - arr[qmin.front()] > sum) { //不达标break;} else {r++;}}count += r - l;//记录子数组达标的数量//检查队首元素是否过期if (qmax.front() == l) {qmax.pop_front();}if (qmin.front() == l) {qmin.pop_front();}}return count;
}vector generateRandomArray(int maxL, int maxV) {int len = rand() % (maxL + 1);vector arr(len);for (int i = 0; i < len; i++) {arr[i] = (rand() % (maxV + 1)) - (rand() % (maxV + 1));}return arr;
}void printArray(vector &arr) {if (arr.size()) {for (int i = 0; i < arr.size(); i++) {cout << arr[i] << " ";}cout << endl;}
} int main() {int maxL = 100;int maxV = 200;int testTime = 100000;cout << "Begin to test: " << endl;for (int i = 0; i < testTime; i++) {vector arr = generateRandomArray(maxL, maxV);int sum = rand() % (maxV + 1);int ans1 = right(arr, sum);int ans2 = way(arr, sum);if (ans1 != ans2) {cout << "Oops!" << endl;printArray(arr);cout << sum << endl;cout << ans1 << endl;cout << ans2 << endl;break;}if (i % 100 == 0) cout << i << " cases passed!" << endl;}cout << "Test end!" << endl;return 0;
}
  • Java 版
public class AllLessNumSubArray {// 暴力的对数器方法 O(N^3),枚举所有子数组public static int right(int[] arr, int sum) {if (arr == null || arr.length == 0 || sum < 0) {return 0;}int N = arr.length;int count = 0;for (int L = 0; L < N; L++) {for (int R = L; R < N; R++) {int max = arr[L];int min = arr[L];for (int i = L + 1; i <= R; i++) {max = Math.max(max, arr[i]);min = Math.min(min, arr[i]);}if (max - min <= sum) {count++;}}}return count;}//优化:O(N^3) -> O(N)// 结论1:如果[L...R] 范围上的max - min <= sum,那么 L...R 范围的所有子数组都是达标的//	原因:假设 L'...R'是L...R的子数组,因为[L...R]max - [L...R]min <= sum,那么[L'...R']的max'<= max,而[L'...R']的min' >= min,所以max'- min' <= sum,也是达标的//结论2:如果[L...R] 范围上的max - min > sum,那么无论L往左扩还是R往右扩,产生的新的子数组一定是不达标的//思路:个准备一个最大值和最小值的更新结构qmax和qmin,用于维护最大值和最小值//假设窗口一开始为0,此时L = 0,让R往右扩,每扩一次就更新qmax和qmin,如果达标就继续扩,一直到p位置不达标了,那么必须以0开始的子数组达标的数量一共有p-0+1 = p+1个;//然后L往右滑动到1,即L=1的时候,R继续往右扩,看是否达标,直到到达不能达标的位置,则能得到必须以1开始的子数组的达标数量;//......public static int num(int[] arr, int sum) {if (arr == null || arr.length == 0 || sum < 0) {return 0;}int N = arr.length;int count = 0;LinkedList maxWindow = new LinkedList<>();LinkedList minWindow = new LinkedList<>();int R = 0; //不回退//L和R位置都不回退,一共只过N个数,所以时间复杂度是O(n)for (int L = 0; L < N; L++) {  //依次尝试窗口以0开始[0...、[1...、[2...的情况//[L,R),如果L=R,说明窗口内没数while (R < N) { //[L...R,R往右扩,直到初次不达标停止while (!maxWindow.isEmpty() && arr[maxWindow.peekLast()] <= arr[R]) {maxWindow.pollLast();}maxWindow.addLast(R);while (!minWindow.isEmpty() && arr[minWindow.peekLast()] >= arr[R]) {minWindow.pollLast();}minWindow.addLast(R);if (arr[maxWindow.peekFirst()] - arr[minWindow.peekFirst()] > sum) {break;} else {R++;}}count += R - L;//如果L过期,则滚蛋if (maxWindow.peekFirst() == L) {maxWindow.pollFirst();}if (minWindow.peekFirst() == L) {minWindow.pollFirst();}}return count;}// for testpublic static int[] generateRandomArray(int maxLen, int maxValue) {int len = (int) (Math.random() * (maxLen + 1));int[] arr = new int[len];for (int i = 0; i < len; i++) {arr[i] = (int) (Math.random() * (maxValue + 1)) - (int) (Math.random() * (maxValue + 1));}return arr;}// for testpublic static void printArray(int[] arr) {if (arr != null) {for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}}public static void main(String[] args) {int maxLen = 100;int maxValue = 200;int testTime = 100000;System.out.println("测试开始");for (int i = 0; i < testTime; i++) {int[] arr = generateRandomArray(maxLen, maxValue);int sum = (int) (Math.random() * (maxValue + 1));int ans1 = right(arr, sum);int ans2 = num(arr, sum);if (ans1 != ans2) {System.out.println("Oops!");printArray(arr);System.out.println(sum);System.out.println(ans1);System.out.println(ans2);break;}}System.out.println("测试结束");}
}

相关内容

热门资讯

写我的朋友的英语作文400字... 篇一:我的朋友My FriendI have a friend named Lily. She is...
my family 英语作文... my family 英语作文版 篇一My FamilyI come from a small but...
我的梦英语作文(通用6篇) 我的梦英语作文 篇一我一直有一个特殊的梦想,那就是成为一名优秀的英语教师。这个梦想源于我对英语的热爱...
我的朋友英语作文(精选6篇) 我的朋友英语作文 篇一My Friend LucyI would like to introduce...
志愿者的英语作文(精选6篇) 志愿者的英语作文 篇一Volunteering ExperienceI have always be...
英语作文带翻译(经典6篇) 英语作文带翻译 篇一:The Importance of Learning a Second Lan...
英语作文范文分享给朋友【实用... 英语作文范文分享给朋友 篇一:The Importance of ReadingAs an avid...
比较交友性格的好处英语作文【... 比较交友性格的好处英语作文 篇一The Benefits of Comparing Friendsh...
英语作文:Never giv... 英语作文:Never give up永不言弃 篇一Never give upPersistence ...
运动精神英语作文(推荐3篇) 运动精神英语作文 篇一:The Importance of SportsmanshipSportsm...
介绍长城的英语作文【精选4篇... Introducing the Great Wall of ChinaEssay OneThe Gr...
你会选择在家办公的工作吗英语... 你会选择在家办公的工作吗英语作文 篇一Title: Is Working from Home a G...
英语作文My hobby 英语作文My hobby(通用13篇)  在学习、工作、生活中,大家总少不了接触作文吧,借助作文人们...
世界杯英语作文【经典3篇】 世界杯英语作文 篇一Title: The Thrilling Spectacle of the Wo...
写共享单车的利与弊英语作文(... Writing 1: The Pros and Cons of Shared BicyclesSha...
中秋节的英语作文 关于中秋节的英语作文(精选6篇)  在学习、工作乃至生活中,大家都不可避免地会接触到作文吧,写作文可...
有趣的英语班作文【优质3篇】 有趣的英语班作文 篇一《我的英语学习之旅》我在学校里参加了一个有趣的英语班,这个班级给了我一个完全不...
英语范文摘抄初一37篇 英语范文摘抄初一 第一篇After the age of 13, I have come to th...
关于航空宇宙的范文英语【精彩... 关于航空宇宙的范文英语 篇一The Marvels of Aerospace Engineering...
英语作文:机器人的危害(实用... 英语作文:机器人的危害 篇一With the rapid development of techno...