LeetCode 2444. 统计定界子数组的数目

2444. 统计定界子数组的数目

给你一个整数数组 nums 和两个整数 minK 以及 maxK 。

nums 的定界子数组是满足下述条件的一个子数组:

  • 子数组中的 最小值 等于 minK 。
  • 子数组中的 最大值 等于 maxK 。

返回定界子数组的数目。

子数组是数组中的一个连续部分。

示例 1:

输入:nums = [1,3,5,2,7,5], minK = 1, maxK = 5
输出:2
解释:定界子数组是 [1,3,5] 和 [1,3,5,2] 。

示例 2:

输入:nums = [1,1,1,1], minK = 1, maxK = 1
输出:10
解释:nums 的每个子数组都是一个定界子数组。共有 10 个子数组。

提示:

  • 2 <= nums.length <= 10^5
  • 1 <= nums[i], minK, maxK <= 10^6

提示 1

Can you solve the problem if all the numbers in the array were between minK and maxK inclusive?


提示 2

Think of the inclusion-exclusion principle.


提示 3

Divide the array into multiple subarrays such that each number in each subarray is between minK and maxK inclusive, solve the previous problem for each subarray, and sum all the answers.

解法:枚举子数组的一个端点,分析另一个端点的可行的范围

定界子数组满足性质:

  • 子数组不能包含越界的数字 (nums[j] > maxK 或 nums[j] < minK) ;
  • 子数组必须同时包含 maxK 和 minK。

根据上述条件,我们从左到右遍历数组,统计以 j 为右端点的定界子数组数量:

维护左侧上一个越界数字的位置 prev,表示左端点不能等于或越过 prev;
同时,分别维护 maxK 和 minK 在左侧上一次出现的位置 maxl 和 minl,表示左端点必须在 min⁡(maxl, minl) 及其左侧,否则子数组中会缺少 maxK 或 minK;
因此,以 j 为右边界的子数组数量(如果存在)= min⁡(maxl, minl) − prev

class Solution {
    public long countSubarrays(int[] nums, int minK, int maxK) {
        int n = nums.length;
        long ans = 0;
        // prev表示上一个越界的位置下标
        int prev = -1;
        // minl表示上一个minK出现的位置下标
        int minl = -1;
        // minl表示上一个maxK出现的位置下标
        int maxl = -1;

        // nums[i..j]是定界子数组,遍历右端点j,找到符合要求的i的范围
        for (int j = 0; j < n; j++) {
            // i在范围(prev, min(minl, maxl)]内
            if(nums[j] == minK) {
                minl = j;
            }
            if (nums[j] == maxK) {
                maxl = j;
            }
            if (nums[j] < minK || nums[j] > maxK) {
                prev = j;
            }
            // Math.min(maxl, minl) - prev < 0 说明,
            // 此时子数组还不包括minK 或 maxK,不是一个定界子数组
            ans += Math.max(0, Math.min(maxl, minl) - prev);
        }
        return ans;
    }
}

 复杂度分析 

  • 时间复杂度:O(n),n 是 数组 nums 的长度。
  • 空间复杂度:O(1)。
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值