问题描述
小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
问题解析
要解决这个问题,我们需要找到在删除一个元素后,数组中能够得到的长度为 k 的子数组和的最大值。我们可以使用滑动窗口算法来高效地计算这一点。
解决思路:
-
无删除操作的情况: 首先,我们计算在不删除任何元素时,长度为 k 的子数组和的最大值。使用滑动窗口可以在 O(n) 时间内计算所有长度为 k 的子数组的和。
-
删除一个元素的情况: 对于每个可能被删除的元素,我们需要:
- 对数组进行一次滑动窗口计算,考虑删除当前元素后的长度为 k 的子数组。
- 在删除元素后,滑动窗口的范围会变为 k 个元素,但跳过被删除的元素。
-
比较这两种情况: 最终,我们会比较无删除和删除一个元素后的最大和。
实现步骤:
- 计算没有删除的情况:使用滑动窗口算法计算所有长度为 k 的子数组和。
- 删除每个元素的情况:对每个元素,删除它后再计算可能的最大子数组和。
代码实现
def maxSumAfterOneDeletion(n, k, nums):
# Step 1: Compute the sum of all length k subarrays using a sliding window.
window_sum = sum(nums[:k])
max_sum = window_sum # Maximum sum without deleting any element
# Step 2: Calculate the sum for all k-length subarrays after deleting one element.
for i in range(k, n):
# Sliding window for the subarray from i-k+1 to i
window_sum += nums[i] - nums[i - k]
max_sum = max(max_sum, window_sum)
# Step 3: Try deleting each element and calculate the maximum sum
max_sum_after_deletion = float('-inf')
for i in range(n):
# Create a new list without the element nums[i]
new_nums = nums[:i] + nums[i+1:]
# Recalculate sliding window sum for the new list
if len(new_nums) >= k:
window_sum = sum(new_nums[:k])
max_sum_after_deletion = max(max_sum_after_deletion, window_sum)
for j in range(k, len(new_nums)):
window_sum += new_nums[j] - new_nums[j - k]
max_sum_after_deletion = max(max_sum_after_deletion, window_sum)
return max(max_sum, max_sum_after_deletion)
代码解析
1. 函数定义:
def maxSumAfterOneDeletion(n, k, nums):
n: 数组的长度k: 子数组的长度nums: 给定的整数数组
我们需要在给定的数组中,考虑删除一个元素后,找到长度为 k 的子数组和的最大值。
2. 计算不删除任何元素时的最大子数组和
window_sum = sum(nums[:k])
max_sum = window_sum # 最大和初始化为前k个元素的和
- 这部分代码初始化了一个滑动窗口,计算数组前
k个元素的和。window_sum变量保存当前窗口的和。 - 然后,我们将
max_sum初始化为不删除任何元素时的最大子数组和,即前k个元素的和。
接下来,我们使用滑动窗口的方式来计算所有长度为 k 的子数组的和:
for i in range(k, n):
window_sum += nums[i] - nums[i - k]
max_sum = max(max_sum, window_sum)
i从k到n-1,代表了从第k个元素开始,滑动窗口向右移动。- 对于每次滑动,我们通过
window_sum += nums[i] - nums[i - k]更新当前窗口的和。即我们从窗口中去掉了元素nums[i - k],并加入了元素nums[i],这样就能计算出新的窗口和。 - 之后,我们更新
max_sum,确保保存当前最大值。
3. 删除一个元素后的最大子数组和
接下来,我们考虑删除数组中的每个元素。对于每个删除的元素,我们需要重新计算移除该元素后的所有长度为 k 的子数组的和。
max_sum_after_deletion = float('-inf') # 用于记录删除一个元素后的最大和
max_sum_after_deletion初始化为负无穷,用于保存删除一个元素后可能的最大子数组和。
然后,我们遍历数组中的每个元素,模拟删除该元素的情况:
for i in range(n):
new_nums = nums[:i] + nums[i+1:]
- 这里,
new_nums是一个新数组,它是原数组nums删除第i个元素后的结果。我们通过nums[:i]和nums[i+1:]将原数组切分为两部分,合并起来。
对于每一个删除后的新数组,我们再次使用滑动窗口方法计算其所有长度为 k 的子数组的和:
if len(new_nums) >= k:
window_sum = sum(new_nums[:k])
max_sum_after_deletion = max(max_sum_after_deletion, window_sum)
for j in range(k, len(new_nums)):
window_sum += new_nums[j] - new_nums[j - k]
max_sum_after_deletion = max(max_sum_after_deletion, window_sum)
- 对于每个删除元素后的新数组
new_nums,如果新数组的长度大于或等于k,我们计算其前k个元素的和,并通过滑动窗口计算所有长度为k的子数组和的最大值。 - 我们用
window_sum += new_nums[j] - new_nums[j - k]来更新窗口和,和之前一样,滑动窗口逐步计算所有可能的子数组和。
4. 计算最终的结果
最后,返回 max(max_sum, max_sum_after_deletion),即比较不删除元素和删除一个元素后的最大子数组和,返回其中较大的那个值。
return max(max_sum, max_sum_after_deletion)
时间复杂度分析:
-
滑动窗口计算最大子数组和:
- 对于每个删除元素后的新数组,重新计算子数组和需要 O(n) 的时间。
- 在最坏的情况下,我们需要删除每个元素,循环次数是
n,因此删除一个元素后的子数组和计算总共需要 O(n^2) 的时间。
-
整体时间复杂度:最坏情况下,整体的时间复杂度是 O(n^2)。由于对于每个元素我们都要创建新的数组并重新计算子数组和。
优化:
这种实现方法的时间复杂度是 O(n^2),可以进一步优化。如果数组不大,可以使用更高效的方式处理删除操作,比如考虑从滑动窗口的角度优化。
总结:
- 代码通过滑动窗口计算不删除元素时的最大子数组和。
- 对于每个元素,模拟删除它,计算删除后的最大子数组和。
- 最终返回两者的较大值作为结果。