滑动窗口求固定长度无重复元素子数组的最大和

1次阅读

滑动窗口求固定长度无重复元素子数组的最大和

本文详解如何使用优化的滑动窗口算法,高效求解长度为 k 且所有元素互异的子数组的最大和,重点修复频次统计与窗口收缩逻辑中的常见错误。

本文详解如何使用优化的滑动窗口算法,高效求解长度为 k 且所有元素互异的子数组的最大和,重点修复频次统计与窗口收缩逻辑中的常见错误。

在解决「固定长度、元素互异子数组的最大和」这类问题时,核心挑战在于实时、准确地判断当前滑动窗口内是否恰好包含 k 个互异元素。初学者常引入布尔标志(如 canIcount)来标记窗口合法性,但该方式极易因状态更新不及时而失效——例如当窗口中存在多个重复元素时,无法可靠判定何时恢复“合法”状态。

正确思路是:直接利用哈希表(字典)的键数量作为唯一性判据。因为 len(eleToFreq) == k 当且仅当当前窗口内恰好有 k 个不同元素(且窗口长度恒为 k),这比维护额外标志更鲁棒、更简洁。

以下为优化后的完整实现(基于 Python):

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)时更新最大和                 if len(freq) == k:                     max_sum = max(max_sum, sum_so_far)                  # 收缩左边界:移除 nums[left]                 left_val = nums[left]                 if freq[left_val] == 1:                     freq.pop(left_val)                 else:                     freq[left_val] -= 1                 sum_so_far -= left_val                 left += 1          return max_sum

关键修正点说明

  • 去标志化:摒弃易错的 canIcount 标志,改用 len(freq) == k 直接、精确判断窗口合法性;
  • 窗口收缩逻辑修正:原代码中 if eleToFreq[a[i]] >= 1 会导致空键访问或逻辑错误;正确做法是先检查频次是否为 1(需 pop),否则减 1;
  • 结构精简:合并重复逻辑,使用 for … enumerate 替代手动双指针 while 循环,提升可读性与 Pythonic 风格;
  • 边界处理简化:无需预先 if len(set(nums))

⚠️ 注意事项

  • 时间复杂度为 O(n),每个元素最多被访问两次(入窗 + 出窗);空间复杂度为 O(min(k, n)),由哈希表存储的最多 k 个不同元素决定;
  • 切勿在收缩时使用 del freq[left_val] 而不检查存在性,应统一用 pop() 或条件判断;
  • 若题目要求返回子数组而非和,可在 len(freq) == k 时记录 left 和 right 下标。

该解法兼顾正确性、简洁性与工程实践性,是滑动窗口处理“定长+去重”约束的经典范式。

text=ZqhQzanResources