LeetCode每日一题2025-04-29
2962. 统计最大元素出现至少 K 次的子数组 M
给你一个整数数组 nums 和一个 正整数 k 。
请你统计有多少满足 「 nums 中的 最大 元素」至少出现 k 次的子数组,并返回满足这一条件的子数组的数目。
子数组是数组中的一个连续元素序列。
示例 1:
输入:nums = [1,3,2,3,3], k = 2
输出:6
解释:包含元素 3 至少 2 次的子数组为:[1,3,2,3]、[1,3,2,3,3]、[3,2,3]、[3,2,3,3]、[2,3,3] 和 [3,3] 。
示例 2:
输入:nums = [1,4,2,1], k = 3
输出:0
解释:没有子数组包含元素 4 至少 3 次。
提示:
- 1
<= nums.length <= - 1
<= nums[i] <= - 1
<= k <=
问题分析
给定一个长度为 n 的整数数组 nums 和正整数 k,我们需要统计满足“子数组中数组 nums 的最大元素至少出现 k 次”的所有连续子数组的个数。
- 全局最大值:数组中所有元素的最大值,记作
M = max(nums)。 - 子数组:数组中任意一段连续的元素序列。
- 目标:统计所有子数组中,元素
M出现次数 ≥k的子数组个数。
直接枚举所有子数组会有 个,无法在 n ≤ 的规模下通过。因此,需要一个 或 的方法。
算法思路
- 全局最大值定位:首先在数组
nums中找到最大的元素M = max(nums)。 - 子数组计数思路:我们要统计所有包含元素
M至少出现k次的连续子数组。 - 滑动窗口+双指针:统计“包含 M 出现次数 < k 的子数组数目”,记为
cnt_less。- 用双指针
left, right扩展窗口,维护窗口中M的出现次数count_M。 - 每次将
right向右移动,若nums[right] == M则count_M += 1。 - 当
count_M >= k时,窗口不再满足“<k”条件,需要移动left且在移动时相应地更新count_M,直到count_M < k。 - 对于每一个
right,当前满足< k的最长窗口长度是right - left + 1,将其累加到cnt_less。
- 用双指针
- 总子数组数目:
- 答案:,即所有子数组减去不满足条件的那些。
时间复杂度
时间复杂度:,left 和 right 指针各最多移动 次。
空间复杂度:,只使用常数级的额外变量。
代码分解
-
找最大值 :
M = max(nums) -
初始化
1
2
3
4n = len(nums)
left = 0
count_M = 0
cnt_less = 0 -
滑动窗口循环
1
2
3
4
5
6
7
8
9
10for right in range(n):
if nums[right] == M:
count_M += 1
# 收缩左端,直到 count_M < k
while count_M >= k:
if nums[left] == M:
count_M -= 1
left += 1
# 累加以 right 结尾的不满足子数组数
cnt_less += (right - left + 1) -
计算并返回结果
1
2total = n * (n + 1) // 2
return total - cnt_less
代码实现
1 | class Solution: |
-
输入:
nums = [1,3,2,3,3],k = 2- 全局最大值
M = 3 - 统计
<2次的子数组数cnt_less = 15 - 6 = 9(总子数组 15 个,满足条件 6 个) - 返回
15 - 9 = 6,与题目示例一致。
- 全局最大值
-
输入:
nums = [1,4,2,1],k = 3M = 4,在任何子数组中最多出现 1 次,均 <3cnt_less = total = 10,所以返回10 - 10 = 0。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Stay hungry. Stay foolish.!
评论
