解决最大子数组之和的两种方法

背景

  1. 自己码了一遍这个算法,然后网上找了下题目分析。发现了更好的解法:解决最大子数组之和的三种方法,在此记录一篇简述心得。

题目

求一个整数数组中[和最大]的连续子数组

  1. 拿到题目自己理解的有误,一直在想怎么一边计算和一边记录 start&end 索引。其是题目没有这个要求。

解法一,思路如下:

  1. 因为最大子数组 startIndex 和 endIndex 不确定,所以肯定需要for循环遍历来确定。
  2. 因为遍历所有元素作为 startIndex 需要一层for循环,另外遍历所有元素作为endInex也需要一层for循环。所以一定需要两层for循环。
  3. 计算 endIndex 思路:例如数组是[a, b, c, d, e],如果a + b > 当前最新的count,则更新 count;否则不更新,继续累加。
  4. 2层遍历结束,最终的 count 就是最大的和。
public static void solution(int[] array) {
        int startIndex = 0;
        int endIndex = 0;
        int count = 0;
        //第一层遍历:所有元素作为 startIndex
        for (int i = 0; i < array.length; i++)  {
            // 注意1:一定需要一个 tempCount 来一直做累加,然后把最终值赋给count
            int tempCount = 0;
            for (int j = i; j < array.length; j++) {
            	//第二层遍历:计算 i 作为 startIndex 时,哪个元素为和最大的的 endIndex
                tempCount += array[j];
                if (tempCount > count) {
                	//注意2:此处有个关键代码[ tempCount > count ],通过此条件更新最终结果
                    startIndex = i;
                    endIndex = j;
                    count = tempCount;
                }
            }
        }
        System.out.println("startIndex:" + startIndex + ", endIndex:" + endIndex + ", count:" + count);
    }

解法二,思路如下:

  1. 先说一下我的思路:数组 [a, b, c, d, e] 中可能有负数,否则最大值就是整个数组元素之和。我们开始遍历累加数组元素,例如 a+b,假如a为正数(如果a为负数则从b开始计算),如果 b 为负数,则判断 b+c 是否为正数,如果b+c是正数则当前最大子序列为 a+b+c,否则再计算 b+c+d是否为正数。以此类推。那么问题来了,虽然感觉这思路方向没问题,但是代码不好写,首先第一层遍历少不了,但是判断 b+c+d 是否为正数是用递归还是用遍历呢?如果用遍历那么效率和解法一相同,用递归代码又变复杂了。怎么办?
  2. 答案就在这篇文章:解决最大子数组之和的三种方法
  3. 我的思路错误在:遍历是从左到右,但是另一块判断加上右边的b 后对总和是否是正向影响。一左一右,方向不一致,出现了矛盾点。
  4. 正确的思路:遍历依然是从左到右,但是累加判断分拆为两点
    1. [条件1]:a+b后和 是否大于 当前的最大值,如果大于当前的最大值则更新最大值
    2. [条件2]:a+b之后的和是否小于b,如果小于b,代表b之前的元素之和是负数,需要抛弃,b为最新的startIndex。
    3. 累加的判断拆分为以上两点,但是写代码时要先 判断[条件2],再判断[条件2],因为更新累加和的逻辑一定在代码块的末尾位置。
public static void solution(int[] arr) {
        int max=0;
        int thisMax=0;
        for (int i=0;i<arr.length;i++) {
            thisMax+=arr[i];
            //若thisMax有没有令arr[i]变小,则从arr[i]重新开始累计
            if (thisMax<arr[i])  {
                thisMax=arr[i];
            }
            //若当前的thisMax已经比上一个max大,则将thisMax记为max
            if (thisMax>max) {
                max=thisMax;
            }
        }
        System.out.println(max);
    }

总结:个人觉得以上两种解法就比较清晰,主要记录反思自己思路和正确答案之间的偏差。(文中引用博客使用递归的分治法不好理解,就不再解释)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值