Given an integer array nums
and two integers left
and right
, return the number of contiguous non-empty subarrays such that the value of the maximum array element in that subarray is in the range [left, right]
.
The test cases are generated so that the answer will fit in a 32-bit integer.
Example 1:
Input: nums = [2,1,4,3], left = 2, right = 3 Output: 3 Explanation: There are three subarrays that meet the requirements: [2], [2, 1], [3].
Example 2:
Input: nums = [2,9,2,5,6], left = 2, right = 8 Output: 7
Constraints:
1 <= nums.length <= 105
0 <= nums[i] <= 109
0 <= left <= right <= 109
题目:给定一串数组,和左右边界left, right。返回连续非空子数组的个数,这些子数组需要满足的条件是:子数组中最大值要在left和right之间。
思路:
1, 当子数组都在left,right之间时:left=2, right=8, nums=[2, 5, 6]. 子数组个数为 [2],[5],[6],[2,5],[5,6],[2,5,6], 3 + 2 + 1 = 6;可以看出,后面每新增一个在[left, right]中间的值都增加了n个符合条件的子序列。例如nums=[2, 5, 6, 7]的话,比之前增加[2, 5, 6, 7],[5,6,7],[6,7],[7],4个符合条件的子序列。即[2, 5, 6, 7]符合条件的子序列为4+3+2+1=10;
2,当子数组最后一个值比left小时:left=2, right=8, nums=[2, 5, 1]. 子数组个数为[2],[5],[2,5],[5,1], [2, 5, 1] , 2 + 2 + 1 = 5; 比第一种情况少了[1],1个,也就是说最后的值比left小的话只贡献了[5, 1]和[2, 5, 1] 2个;如果子序列变为[2, 5, 1, 1],则最后一个1新增的符合条件的子序列为[2, 5, 1, 1]和[5, 1, 1]。新增的符合条件子序列个数为n - Cmin个。Cmin为当前连续的比left小的元素个数。这里为[1, 1],Cmin=2, n = 4.因此最后一个元素1贡献的子序列个数为2;
3, 当子数字最后一个值比right大时:left=2, right=8, nums=[2, 5, 9],则最后一个元素9贡献的子数组个数为0,因为只要包含9,则子序列最大值都不符合条件了。
因此,可以线性扫描,用start记录当前子序列最靠前的开始点,扫描到新的值nums[i]时有三种情况:
1,nums[i] > right :这种最简单,结果数不变,将更新start为i+1,以确保子序列不包含nums[i];
2, nums[i] < left: 更新Cmin++, 更新结果 res += i - start + 1 - Cmin.
3, left <= nums[i] <= right:更新Cmin=0, 更新结果
代码:
class Solution {
public:
int numSubarrayBoundedMax(vector<int>& nums, int left, int right) {
int res = 0, start = 0;
int Cmin = 0; //记录连续的比left小的元素个数
for(int i = 0; i < nums.size(); i++){
if(nums[i] > right) {
start = i + 1;
Cmin = 0;
} else if(nums[i] < left){
Cmin++;
res += i - start + 1 - Cmin;
} else {
Cmin = 0;
res += i - start + 1;
}
}
return res;
}
};
time:O(N), space: O(1)