LeetCode 1695中等滑动窗口
删除子数组的最大得分 图解题解
这道题到底在问什么
给你一个正整数数组 nums ,请你从中删除一个含有 若干不同元素 的子数组 。 删除子数组的 得分 就是子数组各元素之 和 。 返回 只删除一个 子数组可获得的 最大得分 。 如果数组 b 是数组 a 的一个连续子序列,即如果它等于 a[l],a[l+1],...,a[r] ,那么它就是 a 的一个子数组。
- nums
- [4,2,4,5,6]
- 输出
- 17
先想最直接的笨办法
数组/字符串状态条跟着代码走:推进语句是:ans = max(ans, cur)。处理过的部分不再重新枚举。(动画第 10 步)
最优解:一步一步想明白
- 3下面 9 步动画会按主解代码推进,而不是泛泛讲题型。
- 4先读清 删除子数组的最大得分 的输入输出数组/字符串状态条跟着代码走:先把示例输入映射到代码参数:def maximumUniqueSubarray(self, nums):。
- 5seen = set();l = 0;cur = 0数组/字符串状态条跟着代码走:开局只立住必要变量:seen = set();l = 0;cur = 0。
- 6for r, x in enumerate(nums):数组/字符串状态条跟着代码走:主流程从这里开始:for r, x in enumerate(nums):。
- 7根据题意分情况数组/字符串状态条跟着代码走:题目条件落到这一行:满足条件就进入对应分支。
- 8cur -= nums[l]数组/字符串状态条跟着代码走:对应代码:cur -= nums[l]。这一行决定当前轮对答案有什么贡献。
- 9while x in seen 持续删除数组/字符串状态条跟着代码走:边界跟着代码看:cur += x。
- 10ans = max(ans, cur)数组/字符串状态条跟着代码走:推进语句是:ans = max(ans, cur)。处理过的部分不再重新枚举。
- 11return ans数组/字符串状态条跟着代码走:到这里,seen 已经能表达题目要求。
- 12return:return ans数组/字符串状态条跟着代码走:最后检查返回形态:返回值、原地修改或设计类状态,要和 LeetCode 判题方式一致。
- 15记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
⚠️ 容易写错的地方
✗ 错:只删除一次左端
✓ 对:while x in seen 持续删除
重复元素可能不在最左端
✗ 错:窗口和忘记减左端
✓ 对:移出元素时同步扣分
答案依赖窗口和
完整代码(Python)
Python
class Solution:
def maximumUniqueSubarray(self, nums):
seen = set()
l = 0
cur = 0
ans = 0
for r, x in enumerate(nums):
while x in seen:
seen.remove(nums[l])
cur -= nums[l]
l += 1
seen.add(x)
cur += x
ans = max(ans, cur)
return ans复杂度
时间复杂度
O(n)
每个元素进出窗口一次
空间复杂度
O(n)
集合保存窗口元素
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 删除子数组的最大得分 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「滑动窗口」,换最直接的暴力解会差在哪?+
滑动窗口抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。