【LeetCode】795.区间子数组个数

题目描述

给你一个整数数组 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 <= 105
0 <= nums[i] <= 109
0 <= left <= right <= 109

方法:一次遍历

class Solution {
public:
    int numSubarrayBoundedMax(vector<int>& nums, int left, int right) {
        int last1 = -1, last2 = -1;
        int res = 0;
        for(int i=0; i<nums.size(); i++){
            if(nums[i] >= left && nums[i] <= right){
                last1 = i;
            }
            else if(nums[i] > right){
                last2 = i;
                last1 = -1;
            }
            if(last1 != -1){
                res += last1 - last2;
            }
        }

        return res;
    }
};

心得

  • 这道题我一开始想用动态规划, dp[i][j] 表示 下标从 i 到 j 的数组是否满足条件,满足则为1,然而求解不出来。

  • 最终还是用了逐个遍历的方法:

    • 如果当前遍历的元素在 [left, right] 区间内,则可以循环遍历到出现 >right 的元素为止;
    • 如果当前遍历的元素 <left,则从该元素开始遍历到最末尾,如果有出现在区间 [left, right] 的元素,则可以加入结果计数(显然,如果出现极端情况,在这里每次都遍历到最末会TLE)。
    • 如果当前遍历的元素 >right,则该元素作为分割点,直接考虑下一个元素。

    因此我的方法是不可行的,接下来介绍两种方法。

方法:一次遍历

  • 思路:
  1. 一个子数组的范围落在区间 [left, right] 表示数组中不能出现大于 right 的元素,且至少包含一个在区间内的元素。
    我们将元素分为三类:

    • 小于 left,用 0 表示;
    • 落在区间 [left, right] 内,用 1 表示;
    • 大于 right,用 2 表示。

    因此,子数组中不能含有 2 ,且至少包含一个 1 。

  2. 我们依次遍历元素,将子数组区间的右端点固定为 i,求解有多少合法的子区间。过程中需要维护两个变量:

    • last1,表示上一次 1 出现的位置,默认为 -1;
    • last2,表示上一次 2 出现的位置,默认为 -1;

    如果last1不为-1,那么子数组以 last1为右边界点,合法的左边界点可以落在 (last2, last1) 之间。这样的左边界点有 last1 - last2 个。

  3. 因此,我们遍历数组:

    • 如果 left <= nums[i] <= right ,则 last1 = i ;
    • 如果 nums[i] > right ,则 last2 = i,last1 = -1 。

    最后累加 last1 - last2,即完成计算。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值