[杨小白]_leetcode_力扣_11月24每日一题-795. 区间子数组个数

53 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

前言

小白算法比较菜,希望能激励我每日更新,从leetcode第一题开始,2022年目标1900分,1823分了!!

11月24日每日一题

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

代码

这里分享两个做法,第一个算是暴力做法吧,首先遍历一遍,把在范围内的置1,小于left的置0,大于right的置-1

因为题目要求是最大值在left到right之间就可以,所以是可以出现小于left的情况的。

然后两层while循环,找到l和r之间不含有-1的区间段,计算这区间有多少种符合条件的,这里呢我用了前缀和。而且当l到r之间没有0的时候,直接返回(len + 1) * len / 2 即可。如果不加这一步的话,有一个测试用例会超时。

最后提交是10ms


方法二,是看评论区大佬的做法,很好理解,题目要求是最大值在left到right之间 == 最大值小于等于right - 最大值小于等于(left - 1)

至于求小于X的连续子数组,就很好做了,只需要O(n)复杂度,是个经典的题性,需要记住。

//方法一
class Solution {
    public int numSubarrayBoundedMax(int[] nums, int left, int right) {
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] >= left && nums[i] <= right) {
                nums[i] = 1;
            } else if(nums[i] <left){
                nums[i] = 0;
            } else {
                nums[i] = -1;
            }
        }
        int res = 0;
        int l = 0;
        int r = 0;
        while(r < nums.length) {
            while(r < nums.length && nums[r] == -1) {
                r++;
            }
            l = r;
            while(r < nums.length && nums[r] != -1) {
                r++;
            }
            //求l到r(不算r)之间,有多少符合要求的
            res = res + fun(nums, l ,r);
        }
        return res;
    }

    private int fun(int[] nums, int l, int r) {
        int[] preSum = new int[r - l + 1];
        boolean flag = true;
        for (int i = l; i < r; i++) {
            preSum[i + 1 - l] = preSum[i-l] + nums[i];
            if(nums[i] == 0) {
                flag = false;
            }
        }
        if(flag == true) {
            long len = r - l;
            return (int)((len + 1) * len / 2);
        }
        int res = 0;
        for (int i = l; i < r; i++) {
            for (int j = i; j < r; j++) {
                if (preSum[j - l + 1] - preSum[i - l] != 0) {
                    res++;
                }
            }
        }
        return res;
    }
}
//方法二
class Solution {
    public int numSubarrayBoundedMax(int[] nums, int left, int right) {
        return numSubarrayBoundedMax(nums,right) - numSubarrayBoundedMax(nums,left - 1);
    }

    private int numSubarrayBoundedMax(int[] nums, int left) {
        int res = 0;
        int temp = 0;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] <= left) {
                temp++;
            } else {
                temp = 0;
            }
            res += temp;

        }
        return res;
    }
}

3.结束

1823分了。希望早日1900。knight最低是 1875.65,加油!

image.png