刷题的日常-区间子数组个数

71 阅读2分钟

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

刷题的日常-2022年11月24号

一天一题,保持脑子清爽

区间子数组个数

来自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]

理解题意

通过题意,我们可以将信息整理如下:

  • 题目给出一个数组 和 一个范围
  • 要求找出最大值在范围内的子数组的数量

做题思路

看题目脑子里的想法是单调栈去做,然后发现边缘条件过多就放弃了,然后看了题解 (*^_^*)
根据题意,我们要找的范围是出现大于等于 left 并且 小于等于 right,而且没有出现大于right的子数组。 我们先找到第一个大于right的索引位置作为起始点。然后往后扫描,如果出现过满足条件的最大值,那么以当前索引为结束的位置,满足条件的子数组个数就是 最后一个满足条件的索引 减去 上一个大于right的索引位置。步骤如下:

  • 开辟左右边界,和一个结果进行记录
  • 循环数组元素
    • 如果满足条件,将右边界更新为当前索引
    • 如果大于right,则将左边界更新为当前位置,右边界重置为-1
    • 最后判断是否存在满足条件的右边界,存在将左右边界的差值加上去
  • 返回最终的统计结果

代码实现

代码实现如下,因为只需要扫描一次,所以时间复杂度为O(n),n为数组长度:

public class Solution {
    public int numSubarrayBoundedMax(int[] nums, int left, int right) {
        int res = 0, l = -1, r = -1, num;
        for (int i = 0; i < nums.length; i++) {
            num = nums[i];
            if (num >= left && num <= right) {
                r = i;
            } else if (num > right) {
                l = i;
                r = -1;
            }
            if (r != -1) {
                res += r - l;
            }
        }
        return res;
    }
}

image.png