Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Miykael_xxm
leetcode
提交
267992d9
L
leetcode
项目概览
Miykael_xxm
/
leetcode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
L
leetcode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
267992d9
编写于
11月 10, 2019
作者:
L
luzhipeng
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: #1186
上级
f7860395
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
161 addition
and
0 deletion
+161
-0
problems/1186.maximum-subarray-sum-with-one-deletion.md
problems/1186.maximum-subarray-sum-with-one-deletion.md
+161
-0
未找到文件。
problems/1186.maximum-subarray-sum-with-one-deletion.md
0 → 100644
浏览文件 @
267992d9
## 题目地址
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。
```
python
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]的子数组最大值
-
上面的上个步骤得到了删除一个的子数组最大值, 不删除的只需要在上面循环顺便计算一下即可
```
python
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])`
, 一个都不删除
```
python
#
# @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
](
./42.trapping-rain-water.md
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录