
本文详解如何使用滑动窗口与哈希表高效求解「长度恰好为 k 且所有元素互异」的子数组的最大和,指出原实现中标志位逻辑缺陷,并给出简洁、鲁棒、符合 python 风格的优化解法。
本文详解如何使用滑动窗口与哈希表高效求解「长度恰好为 k 且所有元素互异」的子数组的最大和,指出原实现中标志位逻辑缺陷,并给出简洁、鲁棒、符合 python 风格的优化解法。
在解决“长度为 k 且元素全部互异的子数组最大和”问题时,核心挑战在于:如何实时、准确地判断当前长度为 k 的滑动窗口内是否所有元素均唯一? 原思路试图用布尔标志 canIcount 跟踪窗口合法性,但其状态更新逻辑存在根本性缺陷——它无法在窗口从“含重复”恢复为“全唯一”时自动重置为 True。事实上,标志位是冗余的:窗口合法当且仅当哈希表中键的数量(即不同元素个数)等于 k。这一观察直接消除了状态管理的复杂性,使逻辑更清晰、更可靠。
以下是基于该思想重构的完整实现:
class Solution:
def maximumSubarraySum(self, nums: List[int], k: int) -> int:
sum_so_far = max_sum = 0
freq = {}
left = 0
for right, val in enumerate(nums):
# 扩展右边界:加入 nums[right]
freq[val] = freq.get(val, 0) + 1
sum_so_far += val
# 当窗口长度达到 k 时,检查并更新答案
if right >= k - 1:
# 合法窗口:恰好 k 个不同元素 → 即哈希表有 k 个 key
if len(freq) == k:
max_sum = max(max_sum, sum_so_far)
# 收缩左边界:移除 nums[left]
left_val = nums[left]
if freq[left_val] == 1:
del freq[left_val]
else:
freq[left_val] -= 1
sum_so_far -= left_val
left += 1
return max_sum✅ 关键改进点说明:
- 去标志位,靠本质判据:用 len(freq) == k 替代易错的 canIcount 标志,语义明确、无状态漂移风险;
- 边界收缩逻辑修正:原代码中 eleToFreq[a[i]] >= 1 误判了删除条件,正确做法是:频次为 1 时 pop,否则减 1;
- 结构扁平化:统一处理左右指针移动逻辑,消除 if/else 分支中的重复代码;
- Python 化写法:使用 enumerate 避免手动索引管理,freq.get(val, 0) 简化计数初始化,变量命名更语义化(如 sum_so_far, max_sum, left/right);
- 无需预校验:删去 if len(set(nums))
⚠️ 注意事项:
- 本解法时间复杂度为 O(n),每个元素最多被访问两次(进/出窗口各一次),空间复杂度为 O(min(k, n))(哈希表最多存 k 个键);
- 切勿在收缩窗口前读取 freq[nums[left]] 后再修改哈希表——必须先判断频次,再决定 del 或 -=;
- 若题目要求返回子数组本身而非和值,只需额外记录触发 max_sum 更新时的 left 和 right 即可。
综上,本题本质是经典滑动窗口 + 频次哈希的组合应用。摒弃模糊的状态标志,回归数学本质(唯一性 ⇔ distinct count == k),辅以清晰的窗口维护流程,即可写出健壮、高效、易维护的工业级代码。










