欢迎光临
我们一直在努力

F.动态规划-入门DP-最大子数组和(最大子段和):1186. 删除一次得到子数组最大和

题目链接:1186. 删除一次得到子数组最大和(中等)

算法原理:

解法:动态规划

11ms击败40.00%

时间复杂度O(N)

空间复杂度O(N)

①状态表示:

由于最多只能删一次,因此到当前位置i时,要么删了要么没删,所以就多加一维,用0记录已删除的状态,用1记录未删除的状态

dp[i][0]:以i位置为结尾且已删除字符的子数组最大和

dp[i][1]:以i位置为结尾且未删除字符的子数组最大和

②状态转移方程:

遍历到当前位置 i 时,“接着前一个”和“以当前位置重新开始”是两个选择,“已删”和“未删”是两种状态,因此:

(1)当遍历到当前位置i,且已删时,一定会有删除,一定会选择,因此有两个选择:

Ⅰ前一个已删+当前值:dp[i-1][0]+nums[i];

Ⅱ前一个未删+当前值删掉:dp[i-1][1]+0;

取两者最大值:dp[i][0]=Math.max(dp[i-1][0]+nums[i],dp[i-1][1]);

(2)当遍历到当前位置i,且未删时,一定没有删除,未必会选择,因此有两个选择:

Ⅰ前一个选,继续接上:dp[i-1][1]+nums[i];

Ⅱ前一个不选,重新开始:nums[i];

取两者最大值:dp[i][0]=Math.max(dp[i-1][1]+nums[i],nums[i]);

简化为:dp[i][1]=Math.max(dp[i-1][1],0)+nums[i];

③初始化:

dp[0][0]=0:第一个位置已删,为0

dp[0][1]=nums[0]:第一个位置未删,为nums[0]

但是要注意的是dp[0][0]的初始化,因为题目要求删除后数组不为空,因此初始化为0是错的吗?也不是,我们可以调整一下,思考:什么情况下,删掉一个元素就空了?那只能是只有一个元素的时候,因此我们只需在动态规划前判断一下是否只有一个,是的话直接返回即可,如果元素数≥2,那么dp[0][0]=0就是可以的,因此此时还有第二个元素,数组必不为空

④填表顺序:

从左往右

⑤返回值:

每一个以 i 位置结尾的子数组的已删和未删的最大和

空间优化版

6ms击败85.45%

时间复杂度O(N)

空间复杂度O(1)

原理同👉动态规划算法-子数组、子串系列:19.最大子数组和(模板题)

由于每次更新只依赖前一个状态,因此我们可以用两个变量来代替数组的更新

Java代码:

class Solution {
public int maximumSum(int[] nums) {
int n=nums.length;
if(n==1) return nums[0];
//dp[i][0]:以i位置为结尾且已删除字符的子数组最大和
//dp[i][1]:以i位置为结尾且未删除字符的子数组最大和
int[][] dp=new int[n][2];
dp[0][0]=0;
dp[0][1]=nums[0];
int ret=nums[0];
for(int i=1;i<n;i++){
dp[i][0]=Math.max(dp[i-1][0]+nums[i],dp[i-1][1]);
dp[i][1]=Math.max(dp[i-1][1],0)+nums[i];
ret=Math.max(ret,Math.max(dp[i][0],dp[i][1]));
}
return ret;
}
}
class Solution {
//空间优化版
public int maximumSum(int[] nums) {
int n=nums.length;
if(n==1) return nums[0];
int dp0=0,dp1=nums[0];
int ret=nums[0];
for(int i=1;i<n;i++){
dp0=Math.max(dp0+nums[i],dp1);
dp1=Math.max(dp1,0)+nums[i];
ret=Math.max(ret,Math.max(dp0,dp1));
}
return ret;
}
}

赞(0)
未经允许不得转载:171主机测评 » F.动态规划-入门DP-最大子数组和(最大子段和):1186. 删除一次得到子数组最大和
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址