开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
题目描述
给你一个整数数组 nums 和两个整数:left 及 right 。找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组,并返回满足条件的子数组的个数。
生成的测试用例保证结果符合 32-bit 整数范围。
示例 1:
输入:nums = [2,1,4,3], left = 2, right = 3
输出:3
解释:满足条件的三个子数组:[2], [2, 1], [3]
示例 2:
输入:nums = [2,9,2,5,6], left = 2, right = 8
输出:7
提示:
- 1 <= nums.length <= 10^5
- 0 <= nums[i] <= 10^9
- 0 <= left <= right <= 10^9
思路分析
题目给我们一个整数数组 nums 和两个整数:left 及 right,我们需要在这个数组中找到满足条件(子数组中的最大值在范围 [left, right] 内)的子数组数目。
我们可以使用双指针的方法来解决这道题目,左端点为第一个小于等于left或right的值,遇到大于left和right的元素时则计算当前区间中满足条件的子数组数量,并且更新左端点。
那么怎么计算当前区间中所有满足条件的子数组数量呢?我们以nums = [1,2,3,2,1,5,6,7,4,2,3,5],left = 3,right = 4为例:
我们可以得到两个满足条件的区间
- 1、
[1,2,3,2,1]
这个区间中大于等于left且小于等于right的值有1个,下标为3的元素3,也就是说子数组应该要包含该元素,我们可以分别计算该元素左右两边区间的子数组数量。
左边区间:[2,3]、[1,2,3]
右边区间:[2]、[2,1]
我们还可以将左右两边的区间组合起来得到新的满足条件的数组:这里的组合数为左边子数组数量 * 右边子数组数量,及2 * 2 = 4。
所以当前区间中符合条件的子数组总数目应该为:左边子数组数量 + 右边子数组数量 + 左边子数组数量 * 右边子数组数量 + 1 = 2 + 2 + 4 + 1 = 9;/
这里的加1是最大值本身,及子数组[3]。
- 2、
[4,2,3]
这个区间中大于等于left且小于等于right的值有2个,分别是下标为0的元素4和下标为2的元素3,也就是说子数组元素应该至少要包含这两个元素之一,所以我们可以这样计算。
(1)计算元素4左右两边区间数目
左边区间:无
右边区间:[2]、[2,3]
这时可以得到子元素数目为0 + 2 + 0 * 2 + 1 = 3
(2)再计算元素3左右两边区间数目
左边区间:[2]、[4,2]
右边区间:无
这时可以得到子元素数目为2 + 0 + 2 * 0 + 1 = 3
观察一下我们会发现这个时候会有重复的子数组:如[4,2,3],所以我们应该要想办法去除掉重复部分的数量,我们每计算完一个满足条件的最大值点时,应该要将该区间的左端点更新为当前最大值点的下标+1处,这样计算出来的数量就不会有重叠的子数组。
在[4,2,3]中,计算完包含元素4的子数组之后,我们应该更新区间为[2,3]再计算包含元素3的子数组数量。
这时候数量为1 + 0 + 1 * 0 + 1= 2
所以总数应该为:9 + 3 + 2 = 14。
具体代码如下:
AC代码
/**
* @param {number[]} nums
* @param {number} left
* @param {number} right
* @return {number}
*/
var numSubarrayBoundedMax = function(nums, left, right) {
let res = 0;
let l = 0,hasMax = [];
const count = (ind,l,hasMax)=>{
let ans = 0;
if(hasMax.length == 0) return 0;
for(let i = 0; i < hasMax.length; i++){
if(i == 0){
ans += ((hasMax[i] - l + 1) || 1) * ((ind - hasMax[i]) || 1);
}else{
ans += ((hasMax[i] - hasMax[i - 1]) || 1) * ((ind - hasMax[i]) || 1);
}
}
return Math.max(ans,0);
};
for(let i = 0; i < nums.length; i++){
if(nums[i] >= left && nums[i] <= right) hasMax.push(i);
if(nums[i] > right){
res += count(i,l,hasMax);
l = i + 1;
hasMax = [];
}
}
return res + count(nums.length,l,hasMax);
};
说在最后
本人为算法业余爱好者,如果上面分享有错误的地方,欢迎指出,感激不尽。