数组arr中必须以i位置结尾的子数组,其最大累加和是多少?

数组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位置,也可能包含前面的元素,这俩方法本质是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰露可乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值