列表

详情


795. 区间子数组个数

给你一个整数数组 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

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int numSubarrayBoundedMax(vector<int>& nums, int left, int right) { } };

python3 解法, 执行用时: 284 ms, 内存消耗: 23 MB, 提交时间: 2022-11-24 09:21:43

class Solution:
    def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
        n = len(nums)
        l, r = [-1] * n, [n] * n
        stk = []
        for i, v in enumerate(nums):
            while stk and nums[stk[-1]] <= v:
                stk.pop()
            if stk:
                l[i] = stk[-1]
            stk.append(i)
        stk = []
        for i in range(n - 1, -1, -1):
            while stk and nums[stk[-1]] < nums[i]:
                stk.pop()
            if stk:
                r[i] = stk[-1]
            stk.append(i)
        return sum((i - l[i]) * (r[i] - i) for i, v in enumerate(nums) if left <= v <= right)

golang 解法, 执行用时: 60 ms, 内存消耗: 7.7 MB, 提交时间: 2022-11-24 09:21:25

// 单调栈 + 枚举元素贡献值
func numSubarrayBoundedMax(nums []int, left int, right int) (ans int) {
	n := len(nums)
	l := make([]int, n)
	r := 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
}

golang 解法, 执行用时: 52 ms, 内存消耗: 7.8 MB, 提交时间: 2022-11-24 09:20:43

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

python3 解法, 执行用时: 88 ms, 内存消耗: 20.6 MB, 提交时间: 2022-11-24 09:20:26

class Solution:
    def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
        # 数组 nums 中所有元素小于等于 lower 的子数组数
        def count(lower: int) -> int:
            res = cur = 0
            for x in nums:
                if x <= lower:
                    cur += 1
                else:
                    cur = 0
                res += cur
            return res
        return count(right) - count(left - 1)

golang 解法, 执行用时: 52 ms, 内存消耗: 7.8 MB, 提交时间: 2022-11-24 09:18:52

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

python3 解法, 执行用时: 84 ms, 内存消耗: 20.8 MB, 提交时间: 2022-11-24 09:18:18

'''
我们可以将数组中的元素分为三类,并分别用 0, 1, 2 来表示:

小于 left,用 0 表示;
大于等于 left 且小于等于 right,用 1 表示;
大于 right,用 2 表示。

那么本题可以转换为求解不包含 2,且至少包含一个 1 的子数组数目。
last1 表示上一次 1 出现的位置,如果不存在则为 −1;
last2 表示上一次 2 出现的位置,如果不存在则为 −1。
'''
class Solution:
    def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
        res = 0
        last2 = last1 = -1
        for i, x in enumerate(nums):
            if left <= x <= right:
                last1 = i
            elif x > right:
                last2 = i
                last1 = -1
            if last1 != -1:
                res += last1 - last2
        return res

上一题