数组arr中必须以i位置结尾的子数组,其最大累加和是多少?
提示:这不是数组累加和三连问题,数组累加和三连是求累加和为k的子数组最大长度
本题求的结果不是子数组累加和为k的最大长度,而是求子数组必须以i结尾,要求这个累加和最大值是多少
本题是下一题的基础知识,必须搞懂本题,才能理解下一题:
数组arr的0–i范围上任选一个子数组的最大累加和是多少?
https://blog.csdn.net/weixin_46838716/article/details/124377952
有以上俩知识点,最终咱们为了破解一个非常重要的题目:
给定数组arr和k,求3个不重叠的长为k的子数组的累加和之和最大值是多少?
https://blog.csdn.net/weixin_46838716/article/details/124378780
题目
数组arr,元素可小于0,等于0,大于0,请问,必须以每个位置i结尾的子数组,其累加和最大值是多少?
一、审题
示例:1 -1 2 -3 3 2
i 0 1 2 3 4 5
(1)子数组必须以i=0位置为结尾的累加和:即1
(2)子数组必须以i=1位置为结尾的累加和:-1 ,1 -1 当然是1-1=0
(3)子数组必须以i=2位置为结尾的累加和:2,-1 2, 1 -1 2,当然是3-1=2
(4)子数组必须以i=3位置为结尾的累加和:-3,2 -3,-1 2 -3, 1 -1 2 -3;当然是2-3=-1
(5)子数组必须以i=4位置为结尾的累加和:3,-3 3,2 -3 3,等,当然是3
(6)子数组必须以i=5位置为结尾的累加和:当然是3+2=5,再往前就是负数
二、解题
实际上,这个题,咱们看的就是子数组必须以i结尾,累加和dp[i]
它可能只包含arr[i],而没有前面的元素
它可能既包含arr[i],也包含前面的元素
即使以i结尾,可能会涉及整个数组,所以,我们要从头到尾累加到cur上,
途中一旦发现cur<0,咱就给它变0,不要了,因为负的加进来没啥卵用,我们只要某个位置j–i
保证最大累加和,即使负,也要保证负最少
比如:求下面i位置结尾的累加和,
cur=0,
来到0位置,cur=1,更新max=1;
来到1位置,cur=1-1=0,更新max=1;
来到2位置,cur=0+2=2,更新max=2;
来到3位置,cur=2-3=-1,更新max=2;但是,此时cur<0了,所以咱这个cur清零,不要前面这些元素,否则带-数只会让后面的和更小!
来到3位置,cur=0+3=3,更新max=3;【这就是结果,只要了i位置,没有前面的】
代码很简单,结果返回每一个i位置结尾的子数组的最大累加和
//单独说:arr中必须以i结尾的子数组,最大累加和是多少?
public static int[] arrMustBeiEnd(int[] arr){
int N = arr.length;
//用cur套
int[] ans = new int[N];
int cur = 0;
for (int i = 0; i < N; i++) {
cur += arr[i];//加上arri表示必须以i结尾
ans[i] = cur;
cur = cur < 0 ? 0 : cur;//小于就要清零
}
return ans;
}
public static void test2(){
int[] arr = {1, -1, 2, -3, 3, 2};
int[] ans = arrMustBeiEnd(arr);
for(Integer x : ans) System.out.print(x +" ");
}
还有一个动态规划版本的代码:
填一个1维表格,非常简单
定义dp[i]:是必须以i结尾子数组的最大累加和 显然:
(1)dp[i]可能只有i位置
(2)dp[i]也可能包含前面的位置
//单独说:arr中必须以i结尾的子数组,最大累加和是多少?用dp版本
//定义dp[i]是必须以i结尾子数组的最大累加和,可能只有i位置,也可能包含前面的位置
public static int[] arrMustBeiEndDP(int[] arr){
int N = arr.length;
//用cur套
int[] dp = new int[N];
dp[0] = arr[0];//0位置就它了,往后i可能只有i,可能有前面的累加
for (int i = 1; i < N; i++) {
dp[i] = Math.max(arr[i], dp[i - 1] + arr[i]);//这保证了i结尾必须在
}
return dp;
}
public static void test2(){
int[] arr = {1, -1, 2, -3, 3, 2};
int[] ans = arrMustBeiEnd(arr);
int[] ans2 = arrMustBeiEndDP(arr);
for(Integer x : ans) System.out.print(x +" ");
System.out.println();
for(Integer x : ans2) System.out.print(x +" ");
}
总结
提示:重要经验:
1)理解以i结尾的子数组累加和,用cur推导,很容易,cur<0,这意味着只包含i位置的元素,否则就是前面的元素也有
2)理解以i结尾的子数组累加和,用dp填表,可能只包含i位置,也可能包含前面的元素,这俩方法本质是一样的。