题目地址
https://leetcode.com/problems/maximum-subarray-sum-with-one-deletion/
题目描述
给你一个整数数组,返回它的某个 非空 子数组(连续元素)在执行一次可选的删除操作后,所能得到的最大元素总和。
换句话说,你可以从原数组中选出一个子数组,并可以决定要不要从中删除一个元素(只能删一次哦),(删除后)子数组中至少应当有一个元素,然后该子数组(剩下)的元素总和是所有子数组之中最大的。
注意,删除一个元素后,子数组 不能为空。
请看示例:
示例 1:
输入:arr = [1,-2,0,3]
输出:4
解释:我们可以选出 [1, -2, 0, 3],然后删掉 -2,这样得到 [1, 0, 3],和最大。
示例 2:
输入:arr = [1,-2,-2,3]
输出:3
解释:我们直接选出 [3],这就是最大和。
示例 3:
输入:arr = [-1,-1,-1,-1]
输出:-1
解释:最后得到的子数组不能为空,所以我们不能选择 [-1] 并从中删去 -1 来得到 0。
我们应该直接选择 [-1],或者选择 [-1, -1] 再从中删去一个 -1。
提示:
1 <= arr.length <= 10^5
-10^4 <= arr[i] <= 10^4
思路
暴力法
符合知觉的做法是求出所有的情况,然后取出最大的。 我们只需要两层循环接口,外循环用于确定我们丢弃的元素,内循环用于计算subArraySum。
class Solution: def maximumSum(self, arr: List[int]) -> int: res = arr[0] def maxSubSum(arr, skip): res = maxSub = float("-inf") for i in range(len(arr)): if i == skip: continue maxSub = max(arr[i], maxSub + arr[i]) res = max(res, maxSub) return res # 这里循环到了len(arr)项,表示的是一个都不删除的情况 for i in range(len(arr) + 1): res = max(res, maxSubSum(arr, i)) return res
空间换时间
上面的做法在LC上会TLE, 因此我们需要换一种思路,既然超时了,我们是否可以从空间换时间的角度思考呢?我们可以分别从头尾遍历,建立两个subArraySub的数组l和r。 其实这个不难想到,很多题目都用到了这个技巧。
具体做法:
- 一层遍历, 建立l数组,l[i]表示从左边开始的以arr[i]结尾的subArraySum的最大值
- 一层遍历, 建立r数组,r[i]表示从右边开始的以arr[i]结尾的subArraySum的最大值
- 一层遍历, 计算 l[i - 1] + r[i + 1] 的最大值
l[i - 1] + r[i + 1]的含义就是删除arr[i]的子数组最大值
- 上面的这个步骤得到了删除一个的子数组最大值, 不删除的只需要在上面循环顺便计算一下即可
class Solution: def maximumSum(self, arr: List[int]) -> int: n = len(arr) l = [arr[0]] * n r = [arr[n - 1]] * n if n == 1: return arr[0] res = arr[0] for i in range(1, n): l[i] = max(l[i - 1] + arr[i], arr[i]) res = max(res, l[i]) for i in range(n - 2, -1, -1): r[i] = max(r[i + 1] + arr[i], arr[i]) res = max(res, r[i]) for i in range(1, n - 1): res = max(res, l[i - 1] + r[i + 1]) return res
动态规划
上面的算法虽然时间上有所改善,但是正如标题所说,空间复杂度是O(n),有没有办法改进呢?答案是使用动态规划。
具体过程:
- 定义max0,表示以arr[i]结尾且一个都不漏的最大子数组和
- 定义max1,表示以arr[i]或者arr[i - 1]结尾,可以漏一个的最大子数组和
- 遍历数组,更新max1和max0(注意先更新max1,因为max1用到了上一个max0)
- 其中
max1 = max(max1 + arr[i], max0)
, 即删除arr[i - 1]或者删除arr[i] - 其中
max0 = max(max0 + arr[i], arr[i])
, 一个都不删除
# # @lc app=leetcode.cn id=1186 lang=python3 # # [1186] 删除一次得到子数组最大和 # # @lc code=start class Solution: def maximumSum(self, arr: List[int]) -> int: # DP max0 = arr[0] max1 = arr[0] res = arr[0] n = len(arr) if n == 1: return max0 for i in range(1, n): # 先更新max1,再更新max0,因为max1用到了上一个max0 max1 = max(max1 + arr[i], max0) max0 = max(max0 + arr[i], arr[i]) res = max(res, max0, max1) return res # @lc code=end
关键点解析
- 空间换时间
- 头尾双数组
- 动态规划
相关题目
- 42.trapping-rain-water
题目地址 https://leetcode.com/problems/maximum-sum-of-two-non-overlapping-subarrays/ 题目描述 Given an array A of non-negative integers, return the maximum sum of elements in two non-overl…
LeetCode题解113.path-sum-ii题目地址 https://leetcode.com/problems/path-sum-ii/description/ 题目描述 Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. Note: A leaf…
LeetCode题解104.maximum-depth-of-binary-tree题目地址 https://leetcode.com/problems/maximum-depth-of-binary-tree/description/ 题目描述 Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the lo…
LeetCode题解11.container-with-most-water题目地址 https://leetcode.com/problems/container-with-most-water/description/ 题目描述 Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). …
LeetCode题解1131.maximum-of-absolute-value-expression题目地址(1131. 绝对值表达式的最大值) https://leetcode-cn.com/problems/maximum-of-absolute-value-expression/description/ 题目描述 给你两个长度相等的整数数组,返回下面表达式的最大值: |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| …