伴学笔记|豆包MarsCode AI刷题

69 阅读5分钟

问题描述 小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

image.png

题目要求我们从一个给定的整数数组中删除一个元素,并计算删除元素后的最大子数组和。子数组的长度是 k。如果数组的长度恰好为 k,那么我们不进行删除,直接计算原数组的和。我们的目标是通过删除一个元素,找到能得到的最大和。

步骤 1:计算初始子数组和

首先,我们可以使用滑动窗口技巧来解决问题。滑动窗口可以有效地计算出所有长度为 k 的子数组和。我们从数组的第一个元素开始,计算前 k 个元素的和,然后滑动窗口,逐步遍历数组,计算每个窗口对应的子数组和。

例如,对于输入 [2, 1, 3, -1, 4]k = 3,我们可以首先计算第一个子数组 [2, 1, 3] 的和,得到 6。然后滑动窗口,计算下一个子数组 [1, 3, -1] 和,得到 3,接着计算 [3, -1, 4] 和,得到 6。通过这种方式,我们可以快速获得所有长度为 k 的子数组和。

步骤 2:计算删除元素后的最大子数组和

一旦我们得到了所有的长度为 k 的子数组和,接下来就需要考虑删除一个元素后的子数组和。具体做法是,在每个窗口中删除一个元素后,计算剩余部分的和。

对于每个窗口,我们尝试删除窗口内的每一个元素,然后计算删除该元素后的和。例如,假设我们当前在窗口 [2, 1, 3],我们可以删除其中的 2,剩余部分的和就是 1 + 3 = 4;也可以删除 1,剩余部分的和是 2 + 3 = 5;再删除 3,剩余部分的和是 2 + 1 = 3

因此,删除一个元素后,我们需要分别计算删除每个元素后的和,并记录当前窗口下的最大和。然后,我们对所有窗口的结果取最大值。

步骤 3:找出最终结果

经过上述步骤,我们计算了所有长度为 k 的子数组的和,并且每个子数组的删除操作也都计算过了。最后,我们返回所有删除操作后的最大值。

思路分析

  1. 滑动窗口:滑动窗口是一种非常高效的算法技巧,特别适用于求解数组中连续子数组的和、积等问题。在本题中,滑动窗口可以帮助我们高效地计算每个长度为 k 的子数组的和。
  2. 删除元素后的计算:我们在滑动窗口的基础上,需要在每个窗口内删除一个元素,然后重新计算剩余部分的和。这个步骤的重点是要遍历每个窗口中的每个元素,并计算删除该元素后得到的和。我们用一个内层循环来实现这个操作。
  3. 边界处理:题目中提到,当数组的长度恰好为 k 时,我们不需要进行删除操作。此时直接计算整个数组的和即可。这个特殊情况需要单独处理。
  4. 效率:我们通过滑动窗口技巧,避免了多次重复计算子数组和,使得算法的时间复杂度得到了优化。

总结感悟

本题的核心是运用了滑动窗口技巧来快速计算子数组的和,并且利用内层循环计算删除一个元素后的最大和。整个问题可以拆解为两个子问题:首先通过滑动窗口得到所有长度为 k 的子数组的和,其次在每个窗口内删除一个元素并计算新的和。通过这种方式,我们避免了直接暴力枚举所有可能的删除操作,而是通过滑动窗口高效地求解了所有可能的子数组和。

此外,边界处理也是一个重要部分。当数组的长度恰好等于 k 时,不需要删除任何元素,直接计算整个数组的和。在实际编程中,考虑到各种特殊情况和细节是十分重要的,尤其是在涉及滑动窗口或者其他优化算法时,必须确保每一步操作的效率和正确性。

从思维上讲,这道题给我带来了一些启发,尤其是在算法的优化上。面对一些看似复杂的操作,往往可以通过巧妙的技巧(如滑动窗口)来将问题的复杂度降到最低。这种“从简到繁”的思维方式是每个程序员都应该培养的能力。

在实践中,算法的设计不仅仅是关注正确性,更要关注执行效率和可维护性。比如,本题的滑动窗口技巧便能在 O(n) 的时间复杂度下解决问题,显著减少了暴力求