LeetCode每日一题(795. Number of Subarrays with Bounded Maximum)

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:

  • leftright, and nums[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
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值