We are given an array nums
of positive integers, and two positive integers left
and right
(left <= right
).
Return the number of (contiguous, non-empty) subarrays such that the value of the maximum array element in that subarray is at least left
and at most right
.
Example:
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].
Note:
left
,right
, andnums[i]
will be an integer in the range[0, 109]
.- The length of
nums
will be in the range of[1, 50000]
.
这题的关键是如何拆解成子问题, 既不能重叠,又不能使复杂度太大。自己折腾了一上午,也没解决,最终还是看的别人的解析,才搞出来。
我们假设dp[i]是所有以nums[i]为结尾的符合条件的连续数组的计数, 那么我们就可以进一步计算出dp[i+1]的值, 这里需要根据nums[i+1]的值来作出判断:
1. nums[i+1] < left, nums[i+1]自己不能成为一个符合条件的数组, 但是所有以nums[i]为结尾的符合条件的数组再加上nums[i+1]这个元素, 都会是符合条件的数组, 这种的数组的数量恰好是dp[i]个。
2. nums[i+1] > right, 很明显,因为只要包含这种元素就一定不是符合条件的数组,所以dp[i+1]的值一定是0。
3. left <= nums[i+1] <= right, 这情况考虑起来比较绕, 它等于nums[i+1]之前的所有连续的且值<=right的元素的计数+1, 举个例子nums: [2, 8, 1, 4, 5, 6], left: 2, right: 7, 假设我们计算最后一个元素的dp值, i = 5, 因为我们要统计的是所有以nums[5]为结尾的符合条件的数组, 所以只有[1, 4, 5, 6], [4, 5, 6], [5, 6], [6]这四个, 可以看到这里唯一缺少的条件就是前一个>right的元素的索引值, 有了这个索引值我们就可以轻松的计算出dp[i]的值了。
所有的dp[i]值计算出来之后进行加和就是所有符合条件的子数组的数量
代码实现如下(Rust):
impl Solution {
pub fn num_subarray_bounded_max(nums: Vec<i32>, left: i32, right: i32) -> i32 {
// 因为只用到dp[i-1]的值, 所以只需要保存一个值就可以
let mut dp = 0;
let mut ans = 0;
// 上一个>right的元素的索引值
let mut prev = -1;
for (i, n) in nums.into_iter().enumerate() {
if n < left {
ans += dp;
} else if n > right {
dp = 0;
prev = i as i32;
} else {
dp = i as i32 - prev;
ans += dp;
}
}
ans
}
}