一个数组的最大子数组是指该数组的一个和最大的子数组
最大子数组有三种分布情况:
1 最大子数组完全在数组的左半部
2 最大子数组完全在数组的右半部
3 最大子数组跨越数组的中间分布在左右半部,该情况又可分为1 2 3三种子情况
其中前两种分布情况是和主问题相同的子问题,可以使用递归分治去解决,而第三种情况和主问题形式不同,需要考虑继续拆分为三种情况。
由于Java不支持元组形式,因此使用一个result数组保存子数组的信息,result[0]为子数组的下标起点low,result[1]为子数组下标终点high,result[2]为子数组的和sum。
用三个result数组分别保存三种分布情况
result0保存第一种完全在左半部,result1保存第二种完全在右半部,result2保存第三种跨越数组中间。
代码如下:
public class MaxSumSubArray {
public static void main(String[] args) {
int a[]= {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7,1000};
int result[] = Find_MaxiMum_SubArray(a, 0, a.length-1);
int low = result[0];
int high = result[1];
int subsum = result[2];
System.out.println("数组为:");
for(int i:a) {
System.out.print(i+" ");
}
System.out.println();
System.out.println("最大子数组起始下标low:"+low+",最大子数组终止high:"+high+",最大子数组和subsum:"+subsum);
System.out.println("最大子数组为:");
for(int i=low;i<=high;i++) {
System.out.print(a[i]+" ");
}
}
/*最大子数组问题
一个数组的最大子数组是指该数组的一个和最大的子数组
最大子数组有三种分布情况:
1 最大子数组完全在数组的左半部
2 最大子数组完全在数组的右半部
3 最大子数组跨越数组的中间分布在左右半部,该情况又可分为1 2 3三种子情况
用result数组保存子数组的信息,result[0]为子数组的下标起点low,result[1]为子数组下标终点high,result[2]为子数组的和sum
*/
//寻找最大子数组和
public static int[] Find_MaxiMum_SubArray(int[] A,int low,int high) {
//result1保存第1种情况,result1[0]为left_low,result1[1]为left_high,result1[2]为left_sum
int[] result1 = new int[3];
//result2保存第2种情况,result2[0]为right_low,result2[1]为right_high,result2[2]为right_sum
int[] result2 = new int[3];
//result3保存第3种情况,result3[0]为cross_low,result3[1]为cross_high,result3[2]为cross_sum
int[] result3 = new int[3];
if(low==high) {
result1[0] = low;
result1[1] = high;
result1[2] = A[low];
return result1;
}else {
int mid = (low+high)/2;
result1 = Find_MaxiMum_SubArray(A, low, mid);
result2 = Find_MaxiMum_SubArray(A, mid+1, high);
result3 = Find_Max_Crossing_SubArray(A, low, mid, high);
if(result1[2]>=result2[2]&&result1[2]>=result3[2]) {
return result1;
}else if(result2[2]>=result1[2]&&result2[2]>=result3[2]) {
return result2;
}else {
return result3;
}
}
}
//最大子数组横跨中点时的情况
private static int[] Find_Max_Crossing_SubArray(int A[],int low,int mid,int high) {
int left_sum = -9999999;//保存左半子数组的最大和
int sum = 0;//保存当前的最大和
int max_left=0;//保存左半子数组最大和时的左下标
for(int i=mid;i>=low;i--) {
sum=sum+A[i];
if(sum>left_sum) {
left_sum = sum;
max_left = i;
}
}
int right_sum = -9999999;//保存右半子数组的最大和
sum =0;//保存当前的最大和
int max_right=0;//保存右半子数组最大和时的左下标
for(int j=mid+1;j<=high;j++) {
sum = sum+A[j];
if(sum>right_sum) {
right_sum=sum;
max_right = j;
}
}
//用一个结果数组来保存值,result[0]为左子数组的下标,result[1]为右子数组的下标,result[2]为横跨中点的子数组最大的值
int result[] = {max_left,max_right,left_sum+right_sum};
return result;
}
}
结果为: