目录
题目要求
实现思路
代码展示
代码讲解
总结
在一个数组中,找到连续子数组的最大和。重点是1.连续 2.最大 3.和。我们把它翻译成人话,举个例子:arr=[1, -2, 3, 1]。返回值:4。因为arr[2]+arr[3]有最大值4。
结果不是5,因为arr[0]+arr[2]+arr[3]并不连续。(另外,我们不需要返回是谁加谁才有最大值,作为剑指offer中比较简单的题,我们只需要返回最大和即可)
我们需要用到当前和currentSum,前次和lastSum,最大和maxSum等变量,以及一个单层循环来辅助我们完成这个方法。让我们了解一下以上概念。
之前和:每次循环末把之前值更新为当前值。第一次循环没有之前和
当前和:若之前和非负,则说明当前值加之前和后至少不会小于当前值,那么当前和等于当前值加之前。否则说明相加只会更小,那就令当前和等于当前值(贪心算法)。另外,第一次循环时,当前和等于当前元素
最大和:拿最大和与当前和作比较,谁大谁成为本次的最大和。另外,第一次循环时最大和等于当前元素
我们现在用数组 [1, -2, 3, 1] 来理解这个实现思路。
第一次(当前值=1):当前和=1,最大和=1,没有前次和。
第二次(当前值=-2):前次和=1,那么当前和=前次和1+当前值-2=-1,最大和=1不变(因为当前和-1<最大和1)。
第三次(当前值=3):由于前次和=-1<0,因此若让当前和=当前值3+前次和-1,结果一定小于当前值3。如果我们这样,虽然2>1使得最大和=2,但是我们没有得到真正的最大值3。因此当前和=当前值=3,不加上前次和。更新最大和=3(因为当前和3>最大和1)
第四次(当前值=1):前次和=3,那么当前和=前次和+当前值=4,更新最大和=4(因为当前和4>最大和3)
退出循环并返回最大和
package advance.algorithm;
public class MaxSubArr {
public static int solution1(int[] arr) {//beter algorithm
int lastSum=-1,currentSum,maxSum = Integer.MIN_VALUE;
for(int i=0;imaxSum)
maxSum=currentSum;
lastSum=currentSum;
}
return maxSum;
}
//测试
public static void main(String[] args) {
int[] arr={8,1,-3,-3,-1,2,1,-5,4};
System.out.println("max value="+solution1(arr));
}
}
这里简单的讲一下。在solution1()方法中,lastSum初始化时被赋值为-1的原因是我们想要让循环第一次lastSum不参与加和,即模拟第一次循环没有lastSum的效果,而从第一次循环末把lastsum更新为currentSum。
max被设置为了Integer.MIN_VALUE......这又是什么呢?这其实是个常数,表示的是整数类型可以表示的最小数,是-2^31。大家相信也能看出把最大值设置成-2^31用意,就是这样不管循环第一次的元素有多小,max总是比他小,于是max可以被更新为该元素值。
其他代码逻辑在"实现思路"这一模块都讲过了,这里就不再赘述。
其实这道题的解决思路有很多种,有暴力搜索(这个不推荐,不仅代码又臭又长,时间复杂度还是O(n^3)),有动态规划,有前缀和,还有分治算法。而我们这篇文章讲的贪心算法独树一帜。虽然很少人会想到,但也着实是一个非常优秀的方法,他的时间复杂度小于上面讲的大部分算法。
所以推荐大家使用该算法!