该算法核心思想:
任何连续最大子数组必然处于以下三种情况:
- 子数组完全落在中点左边
- 子数组完全落在中点右边
- 子数组横跨中点
所以先求出左边最大的子数组,再找出右边的,然后从中间找。比较大小即可。
中间点的最大子数组容易确定,左右两边的无法确定,所以需要递归,把左右两边的数组分解到只剩一个元素时就能轻松确定。
class MaxRange{
int start;
int end;
int sum;
public MaxRange(int max, int maxLeftIndex, int maxRightIndex) {
this.start=maxLeftIndex;
this.end=maxRightIndex;
this.sum=max;
}
}
public MaxRange findMaxMumSubArray(int[] array,int left,int right){
if (left==right){
return new MaxRange(array[left],left,right);
}
else {
int mid=(left+right)/2;
MaxRange maxRangeLeft=findMaxMumSubArray(array,left,mid);
MaxRange maxRangeRight=findMaxMumSubArray(array,mid+1,right);
MaxRange maxRangeCross=findCrossMax(array,left,mid,right);
return getMax(maxRangeLeft,maxRangeCross,maxRangeRight);
}
}
public MaxRange findCrossMax(int[] array,int left,int mid,int right) {
int sum=0;
int max=sum;
int maxLeftIndex=mid;
for (int i=maxLeftIndex;i>=left;i--){
sum+=array[i];
if (sum>max){
max=sum;
maxLeftIndex=i;
}
}
sum=max;
if (max<=0){
maxLeftIndex=mid+1;
}
int maxRightIndex=mid;
for (int i=maxRightIndex+1;i<=right;i++){
sum+=array[i];
if (sum>max){
max=sum;
maxRightIndex=i;
}
}
return new MaxRange(max,maxLeftIndex,maxRightIndex);
}
public static void main(String[] args) {
Suanfa1 s= new Suanfa1();
Random random=new Random();
int array[]=new int[8];
for (int i=0;i<array.length;i++){
int rand=random.nextInt(1000);
rand=random.nextInt(2)==0?rand*-1:rand;
array[i]=rand;
}
for (int a:array){
System.out.print(a+"__");
}
System.out.println("------------");
System.out.println("");
MaxRange maxRange=s.findMaxMumSubArray(array,0,array.length-1);
for (int i=maxRange.start;i<=maxRange.end;i++){
System.out.print(array[i]+"__");
}
}
运行结果:
246__-82__816__-193__-656__-834__865__645__------------
865__645__
555__755__657__117__-262__-158__-662__-514__------------
555__755__657__117__
851__-893__-882__-126__-850__806__-16__936__------------
806__-16__936__