问题描述:给出一个整数数组,找出一个连续子数组(可以一个都不取和为0),使得这个连续子数组的和是所有连续子数组的和中最大的。
例如给出如下的一个数组:
-211-413-5-2
表中红色标志出来的11-4+13=20就是这个数组中的最大字段和。
首先将问题细分,用sum表示当前情况下最大子段和,用result(初始时为0)记录最终结果。先只考虑一个数:
-2 假设取这个数,则当前子段和sum=-2,sum<0,本着子段和最大的原则这个数肯定不取。sum=0,result=0。
增加一个数:
-211 假设取11,sum=11,sum>result,因为result记录最大结果,所以result=11。
再增加一个数:
-211-4 虽然下一个数是个负数,但加上个这个数还没使sum<0,继续取(后面继续解释没使sum<0就可以继续取)
此时:sum=11-4=7,sum<result,因为最终结果肯定要记录最大的所以result仍然等于11。
再增加一个数:
-211-413 假设取13,sum=7+13=20,sum>result,result保持最大状态,result=20。
再增加一个数:
-211-413-5 假设取-5,sum=20-5=15,sum<result,result保持不变=20。
继续增加:
-211-413-5-2 sum=15-2=13,sum<result,result保持不变=20。
所以最终结果result=20。 现在讨论当sum<0时:
对于第一个-2,若取该数,sum=-2。后面无论取什么数都要减去2,所以当sum<0时(可能是上述情况
取一个数就小于0了,也有可能是取了多个数,这多个数的和小于0)sum应重新置为0,从新的位置开始
重新取。
例如给出这样的一个数组:
-523-647 当取了红色标志的三个数时sum=2+3-6=-1,问题就相当于:
-5-147 很明显sum应该回到初始值0,从4开始重新取(但前面取2、3、-6的过程中记下的最大结果result=5不变)
在后面的sum=4+7=11,sum>result时才更新result=11。
因为数组可能比较长,数组元素又可能比较大,当多个元素加起来时可能会超出int范围,所以用long来
定义sum和result.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc=new Scanner(System.in); //System.out.println("请输入数组长度:"); int n=sc.nextInt(); int a[]=new int[n]; //System.out.println("请输入数组的各个元素值:"); for(int i=0;i<n;i++){ a[i]=sc.nextInt(); } long sum=0,result=0;//初始化,注意此处用long型,防止结果超出int范围 for(int i=0;i<n;i++){ if(sum>0) sum=sum+a[i];//取a[i],将a[i]加到sum中 else sum=a[i];//sum<0,开始从新的位置开始重新取数 result=sum>result?sum:result;//当sum>result时,更新result } System.out.println(result);//输出最后的最大子段和 } }