//寻找最大子数组,使该子数组元素之和为所有子数组中最大的
/*
* 算法:
* 1。利用分治策略,逐层寻找
* 2.最大子数组存在三种情况:若将数组在中间元素位置划分为两部分,则最大子数组可能在中间元素的左半部分、右半部分或者是跨越中间元素的部分。
* 3.现在我们将问题一分为三,在左半部分寻找最大子数组,在右半部分寻找最大子数组,以及在横跨中间的最大子数组中寻找三者之中最大的。而左右两半部分的情况其实是以上情况的递归呈现,所以我们只需针对第三种情况提出解决办法。
* 4.寻找横跨中间位置的最大子数组可以将问题一分为二:我们确定中间元素,在中间元素的左边找最大的数组,右边找到最大的数组,两边的最大子数组可以确定一个边界,使得整个横跨数组为所有横跨数组中最大的一个。
* 5.递归寻找左右两半部分的最大子数组。
*/
package offer.giveme;
public class SmallesSubArray {
public SubArray findMaxInCrossingSubarray(int[] num,int low,int mid,int high){
int left_sum=Integer.MIN_VALUE;
int sum=0;
int max_left=mid;//记录使左半边子数组最大的左边界
for(int i=mid;i>=low;i--){
sum=sum+num[i];
if(sum>left_sum){
left_sum=sum;
max_left=i;
}
}
int right_sum=Integer.MIN_VALUE;
sum=0;
int max_right=mid+1;
for(int i=mid+1;i<=high;i++){
sum=sum+num[i];
if(sum>right_sum){
right_sum=sum;
max_right=i;
}
}
sum=left_sum+right_sum;
return new SubArray(max_left,max_right,sum);
}
public SubArray findMaxSubarray(int[] num,int low,int high){
if(high==low){
return new SubArray(low,high,num[low]);
}
else {
int mid=(low+high)/2;
SubArray leftSub=findMaxSubarray(num,low,mid);
SubArray rightSub=findMaxSubarray(num,mid+1,high);
SubArray crossSub=findMaxInCrossingSubarray(num,low,mid,high);
if(leftSub.sum>=rightSub.sum&&leftSub.sum>=crossSub.sum)
return leftSub;
else if(rightSub.sum>=leftSub.sum&&rightSub.sum>=crossSub.sum)
return rightSub;
else
return crossSub;
}
}
public static void main(String[] args) {
int[] num={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
SubArray subarray=new SmallesSubArray().findMaxSubarray(num,0,num.length-1);
System.out.println("high:"+subarray.high);
System.out.println("low:"+subarray.low);
System.out.println("sum:"+subarray.sum);
for(int i=subarray.low;i<=subarray.high;i++){
System.out.print(num[i]+" ");
}
}
}
class SubArray{
int low;
int high;
int sum=0;
public SubArray(int low,int high,int sum){
this.low=low;
this.high=high;
this.sum=sum;
}
}