难度:中等
关键词:滑动窗口
问题描述
小U手上有一个整数数组,他想知道如果从数组中删除任意一个元素后,能得到的长度为 k 的子数组和的最大值。你能帮小U计算出这个结果吗?
如果数组恰好为 k 个元素,那么不进行删除操作。
测试样例
样例1:
输入:
n = 5,k = 3,nums = [2, 1, 3, -1, 4]
输出:8
样例2:
输入:
n = 6,k = 2,nums = [-1, -1, 5, -2, 3, 4]
输出:8
样例3:
输入:
n = 4,k = 2,nums = [-5, -3, 2, 1]
输出:3
代码思路分解
-
基础处理:
- 如果数组的长度 n 等于 k,说明不可能删除元素,所以直接返回整个数组的和。
-
滑动窗口方法:
-
目的:高效计算长度为 k 的子数组的最大和,而不需要每次重新遍历和求和。
-
方法:
- 首先计算数组中前 k 个元素的总和
current_sum,并将其作为初始的max_sum_k。 - 使用滑动窗口:对于每个新元素
nums[i],将它加入current_sum,并减去滑出窗口的旧元素nums[i - k]。这样就可以在 O(1) 时间内更新current_sum。 - 更新
max_sum_k,保持滑动窗口中长度为 k 的子数组的最大和。
- 首先计算数组中前 k 个元素的总和
-
-
删除每个元素,重新计算最大和:
-
思路:模拟删除数组中的每个元素,并重新计算删除后的数组中长度为 k 的子数组的最大和。
-
方法:
- 使用切片操作
temp_nums = nums[:i] + nums[i + 1:]创建一个新数组,表示删除了索引为 i 的元素。 - 在这个新数组上使用滑动窗口方法,计算长度为 k 的子数组的最大和。
- 在所有删除情况下,记录最大和
max_sum_with_removal。
- 使用切片操作
-
-
返回结果:
- 返回所有情况下长度为 k 的子数组和的最大值
max_sum_with_removal。
- 返回所有情况下长度为 k 的子数组和的最大值
def solution(n, k, nums):
# 如果数组长度正好为 k,不进行删除操作,直接返回总和
if n == k:
return sum(nums)
# Step 1: 使用滑动窗口计算长度为 k 的子数组的初始最大和
max_sum_k = sum(nums[:k]) # 计算前 k 个元素的总和
current_sum = max_sum_k # 当前子数组和
# 使用滑动窗口找到任意长度为 k 的子数组的最大和
for i in range(k, n): # 从索引 k 开始遍历到数组的末尾
current_sum += nums[i] - nums[i - k] # 更新当前子数组和
max_sum_k = max(max_sum_k, current_sum) # 更新最大和
# Step 2: 尝试删除每个元素,计算删除后的长度为 k 的子数组的最大和
max_sum_with_removal = max_sum_k # 初始化删除后子数组和的最大值
for i in range(n): # 遍历每个元素,模拟删除
temp_nums = nums[:i] + nums[i + 1:] # 删除索引为 i 的元素
current_sum = sum(temp_nums[:k]) # 计算删除后数组前 k 个元素的和
max_sum = current_sum # 当前最大和
# 对删除后的数组使用滑动窗口
for j in range(k, n - 1): # 滑动窗口从 k 移动到数组末尾
current_sum += temp_nums[j] - temp_nums[j - k] # 更新当前子数组和
max_sum = max(max_sum, current_sum) # 更新最大和
max_sum_with_removal = max(max_sum_with_removal, max_sum) # 更新全局最大和
return max_sum_with_removal
时间复杂度分析
- 滑动窗口的时间复杂度是 。
- 尝试删除每个元素并重新计算的时间复杂度是 ,因为需要对每个元素都执行一个滑动窗口操作。