【2022-11-24每日一题】795. 区间子数组个数[Medium]

2022-11-24
3分钟阅读时长

2022-11-24每日一题:795. 区间子数组个数

难度: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

方法一:一次遍历

// 写法一
func numSubarrayBoundedMax(nums []int, left int, right int) (cnt int) {
    last1, last2 := -1, -1
    for i, x := range nums {
        if left <= x && x <= right {
            last1 = i
        } else  x > right {
            last1, last2 = -1, i
        }
        if last1 != -1 {
            cnt += last1 - last2
        }
    }
	return cnt
}

// 写法二
func numSubarrayBoundedMax(nums []int, left int, right int) (cnt int) {
    i0, i1 := -1, -1
    for i, x := range nums {
        if x > right { i0 = i }
        if x >= left { i1 = i }
        cnt += i1 - i0
    }
    return cnt
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是 nums 的长度。

  • 空间复杂度:O(1)。只使用到常数个变量。

方法二:计数(区间计数)

// 写法一
func numSubarrayBoundedMax(nums []int, left int, right int) int {
    count := func (lower int) (cnt int) {
        cur := 0
        for _, x := range nums {
            if x <= lower {
                cur++
            } else {
                cur = 0
            }
            cnt += cur
        }
        return cnt
    }
    return count(right) - count(left-1)
}

// 写法二
func numSubarrayBoundedMax(nums []int, left int, right int) int {
    count := func (lower int) (cnt int) {
        cur := 0
        for _, x := range nums {
            cur++
            if x > lower {
                cur = 0
            }
            cnt += cur
        }
        return cnt
    }
    return count(right) - count(left-1)
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是 nums 的长度。

  • 空间复杂度:O(1)。只使用到常数个变量。

方法三:单调栈 + 枚举元素计算贡献

func numSubarrayBoundedMax(nums []int, left int, right int) (ans int) {
    n := len(nums)
    l, r := make([]int, n), make([]int, n)
    for i := range l {
        l[i], r[i] = -1, n
    }
    stk := []int{}
    for i, v := range nums {
        for len(stk) > 0 && nums[stk[len(stk)-1]] <= v {
            stk = stk[:len(stk)-1]
        }
        if len(stk) > 0 {
            l[i] = stk[len(stk)-1]
        }
        stk = append(stk, i)
	}
    stk = []int{}
    for i := n - 1; i >= 0; i-- {
        v := nums[i]
        for len(stk) > 0 && nums[stk[len(stk)-1]] < v {
            stk = stk[:len(stk)-1]
        }
        if len(stk) > 0 {
            r[i] = stk[len(stk)-1]
        }
        stk = append(stk, i)
    }
    for i, v := range nums {
        if left <= v && v <= right {
            ans += (i - l[i]) * (r[i] - i)
        }
    }
	return ans
}

复杂度分析

  • 时间复杂度:O(n),其中 n 是 nums 的长度。

  • 空间复杂度:O(n)。

LeetCode题库地址