区间子数组个数

标签: 数组 双指针

难度: Medium

给你一个整数数组 nums 和两个整数:leftright 。找出 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

Submission

运行时间: 48 ms

内存: 22.0 MB

class Solution:
    def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
        ans = 0
        last1 = last2 = -1
        for i,x in enumerate(nums):
            if left<=x<=right:
                last1 = i
            
            elif right<x:
                last2 = i
                last1 = -1
            if last1 != -1:
                ans += last1-last2
        return ans

Explain

该题解通过遍历数组来计算满足条件的子数组的个数。对于每个元素,检查其是否在给定的[left, right]范围内。如果元素在此范围内,则更新last1为当前索引;如果元素大于right,则更新last2为当前索引,并重置last1为-1,因为当前元素不能成为任何有效子数组的一部分。对于last1不为-1的情况,计算last1与last2之间的差,即满足条件的子数组的数量,累加到答案中。

时间复杂度: O(n)

空间复杂度: O(1)

# 定义解决问题的类
class Solution:
    def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
        ans = 0  # 初始化满足条件的子数组计数为0
        last1 = last2 = -1  # 初始化两个指针,last1跟踪满足条件的最后一个位置,last2跟踪超出right的最后一个位置
        for i, x in enumerate(nums):  # 遍历数组中的每个元素及其索引
            if left <= x <= right:  # 如果元素在[left, right]范围内
                last1 = i  # 更新last1为当前索引
            elif x > right:  # 如果元素超出right
                last2 = i  # 更新last2为当前索引
                last1 = -1  # 重置last1
            if last1 != -1:  # 如果存在有效的last1
                ans += last1 - last2  # 计算并累加满足条件的子数组的数量
        return ans  # 返回结果

Explore

在算法中,last1指针用于跟踪最后一个位置,其对应的数组元素处于给定的[left, right]范围内。last2指针则用于跟踪最后一个元素值超过right的位置。这两个指针的使用是为了确定满足条件的子数组的起始和结束位置。当一个元素的值超出right时,意味着从该元素开始的任何子数组都不能满足条件,因此需要last2来记录这个界限,并通过重置last1来避免错误地计算这些子数组。

如果数组的所有元素都小于left,则last1将始终为-1,因此不会累加任何子数组计数,输出为0。如果所有元素都大于right,则last2会被频繁更新,且每次last1都会被重置为-1,同样导致输出为0。这种情况在算法中得到了正确处理,因为在这两种情况下,确实不存在任何符合条件的子数组。

算法中的条件`left <= x <= right`确保了元素值等于left或right时,这些元素都被视为有效的子数组的一部分。这种处理方式是必要的,因为题目要求统计的是最大值在这个区间内的子数组数量,包括区间的边界值。这确保了所有符合条件的子数组都被正确计数,包括那些包含边界值的子数组。

当元素大于right时,重置last1为-1是因为这样的元素不能作为任何符合条件的子数组的一部分。重置last1确保了从该点开始,不会错误地包括包含该元素的数组作为符合条件的子数组。由于该元素本身及其后的任何组合都将超出所需的最大值条件,因此必须从计数中排除这部分,直到再次遇到符合条件的元素。