区间子数组个数
概述:给你一个整数数组 nums 和两个整数:left 及 right 。找出 nums 中连续、非空且其中最大元素在范围 [left, right] 内的子数组,并返回满足条件的子数组的个数。
输入:nums = [2,1,4,3], left = 2, right = 3
输出:3
解释:满足条件的三个子数组:[2], [2, 1], [3]
输入:nums = [2,9,2,5,6], left = 2, right = 8
输出:7
方法一:双指针
思路:本题可以转换为求解不包含 >right,且至少包含一个 <=right 的子数组数目。所以分别建立快慢指针来表示范围,最后输出快慢指针的差即可。
# 双指针
# 本题可以转换为求解不包含 >right,且至少包含一个 <=right 的子数组数目。
# 所以分别建立快慢指针来表示范围,最后输出快慢指针的差即可。
class Solution:
def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
ans, slow, fast = 0, -1, -1
for i, v in enumerate(nums):
if left <= v <= right:
slow = i
elif v > right:
fast = i
slow = -1
if slow != -1:
ans += slow - fast
return ans
方法二:计数法
思路:思路和上面一致,不同在于定义一个计数函数,最后输出即可。
# 计数法
# 思路和上面一致,不同在于定义一个计数函数,最后输出即可。
class Solution:
def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
def count(lower: int) -> int:
ans = cur = 0
for num in nums:
if num <=lower:
cur += 1
else:
cur = 0
ans += cur
return ans
return count(right) - count(left - 1)
方法三:单调栈
思路:利用栈的特点统计出所有边界点,然后删除重复统计即可。
# 单调栈
# 利用栈的特点统计出所有边界点,然后删除重复统计即可。
class Solution:
def numSubarrayBoundedMax(self, nums: List[int], left: int, right: int) -> int:
ans, n = 0, len(nums)
left_list, right_list = [-1] * n, [n] * n
stack = []
for i in range(n):
while stack and nums[stack[-1]] < nums[i]:
right_list[stack.pop()] = i
stack.append(i)
stack = []
for i in range(n - 1, -1, -1):
while stack and nums[stack[-1]] <= nums[i]:
left_list[stack.pop()] = i
stack.append(i)
for i in range(n):
if left <= nums[i] <= right:
ans += (i - left_list[i]) * (right_list[i] - i)
return ans
总结
思路还算能想到,但是处理边界恶心死了