笔记:求解删除一个元素后长度为k的子数组和的最大值
问题描述
给定一个整数数组,要求找到删除任意一个元素后,能得到的长度为k的子数组和的最大值。如果数组恰好为k个元素,则不进行删除操作。
解题思路
-
边界条件检查:
- 如果k大于数组长度n,则无法找到长度为k的子数组,返回None。
-
初始化:
- 计算第一个长度为k的子数组的和,存储在
current_sum中。 - 初始化结果
res为current_sum。 - 使用双端队列
min_deque来维护当前窗口的最小值索引,确保队列中的索引对应的值是单调递增的。
- 计算第一个长度为k的子数组的和,存储在
-
滑动窗口遍历:
-
从索引k开始,向右遍历数组。
-
在每一步中:
- 更新结果
res为当前窗口的和加上新的元素,减去当前窗口的最小值(通过min_deque[0]获取)。 - 移动窗口,更新
current_sum,通过添加新元素和去掉旧元素来调整和。 - 更新
min_deque,确保它只包含当前窗口的有效索引,并且保持单调递增。这包括移除超出窗口范围的索引和比新元素大的索引。
- 更新结果
-
-
返回结果:
- 最终返回
res,即所有可能的长度为k的子数组(删除一个元素后)的最大和。
- 最终返回
代码实现
python复制代码
from collections import deque
def solution(n, k, nums):
if k > n:
return None
# 计算第一个窗口的和
current_sum = sum(nums[:k])
res = current_sum
# 创建一个双端队列来维护当前窗口的最小值索引
min_deque = deque()
# 初始化双端队列
for i in range(k):
while min_deque and nums[min_deque[-1]] >= nums[i]:
min_deque.pop()
min_deque.append(i)
# 滑动窗口遍历
for i in range(k, n):
# 更新结果
res = max(res, current_sum + nums[i] - nums[min_deque[0]])
# 移动窗口
current_sum += nums[i] - nums[i - k]
# 更新双端队列
while min_deque and min_deque[0] <= i - k:
min_deque.popleft()
while min_deque and nums[min_deque[-1]] >= nums[i]:
min_deque.pop()
min_deque.append(i)
# 返回结果
return res
示例
- 输入:n = 5, k = 3, nums = [1, 2, 3, 4, 5]
- 输出:9(删除1后,子数组[2, 3, 4]的和最大)
注意事项
- 算法的时间复杂度为O(n),其中n是数组的长度。
- 双端队列
min_deque用于高效地找到当前窗口的最小值,从而避免了对每个窗口都重新计算最小值的开销。 - 如果数组恰好为k个元素,则不进行删除操作,直接返回当前窗口的和作为结果。但由于前面的逻辑已经处理了这个情况(因为没有额外的删除操作),所以代码中没有显式检查数组长度是否等于k。