统计「优美子数组」-LeetCode
1248. 统计「优美子数组」
🎯 问题描述(来源于LeetCode)
描述:
给定一个整数数组 nums 和一个整数 k。如果一个连续子数组中恰好有 k 个奇数数字,我们就称这个子数组为「优美子数组」。
请返回这个数组中「优美子数组」的数目。
说明:
- 子数组是连续的。
1 <= nums.length <= 5 * 10^4。
示例:
- 示例 1:
1 | 输入: nums = [1,1,2,1,1], k = 3 |
- 示例 2:
1 | 输入: nums = [2,4,6], k = 1 |
💻 解题思路
思路:滑动窗口 + 容斥原理(基于您的代码)
算法步骤
- 将原数组
nums转换为 0/1 数组:偶数 → 0,奇数 → 1。 - 定义辅助函数
atLeast(x),返回原数组中奇数个数至少为x的连续子数组的个数。- 在
atLeast(x)中:- 使用滑动窗口维护当前窗口内奇数的个数(即
pre)。 - 遍历右端点
right,将nums[right]加入pre。 - 当
pre >= x时,不断移动左指针left(并减去移出的元素),直到pre < x。 - 此时,对于当前右端点,所有左端点 小于
left的子数组(即起点 0 到left-1)都满足奇数个数至少为x,共有left个,累加到答案ans。
- 使用滑动窗口维护当前窗口内奇数的个数(即
- 在
- 利用容斥:恰好为
k个奇数的子数组数 =atLeast(k) - atLeast(k+1)。 - 返回结果。
代码实现(您的代码)
1 | from typing import List |
📊 性能分析
- 时间复杂度:,三次遍历(一次转换 + 两次
atLeast),但每次遍历都是线性的,总体仍为 O(n)。 - 空间复杂度:,仅使用常数个变量(原地修改数组,不算额外空间)。
思考
您的解法非常巧妙,将「恰好 k 个奇数」转化为「至少 k 个」与「至少 k+1 个」的差,完美复用了 LeetCode 930 题的滑动窗口模板。
关键点在于 ans += left:当窗口内奇数个数下降到小于 x 时,left 是第一个使得窗口不满足条件的左边界,因此所有比 left 小的左端点(即 0 到 left-1)与当前右端点构成的子数组都至少包含 x 个奇数。
这种写法简洁高效,无需处理双指针的复杂边界,是本题的经典解法之一。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






