分治策略求解最大连续子数组问题:
原理:如果想要通过递归进行实现,就必须将数组进行子数组的划分,通过子数组划分,出现三种情况可能包含最大子数组,一种是在左边的子数组,一种是在右边的子数组,另一种是跨越中间量的子数组,对于左右子数组便又变成了求解其最大子数组(递归),而跨越中间的子数组需要单独进行遍历求取最大子数组
一直存在理解上的疑惑:如何确定递归得到的就是最大子数组?
通过正向进行递归计算如下:
假定存在如下数组,下列的步骤为依次进行递归的情况:
A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | A9 | A10 | A11 | A12 | A13 | A14 | A15 | A16 |
13 | -3 | -25 | 20 | -3 | -16 | -23 | 18 | 20 | -7 | 12 | -5 | -22 | 15 | -4 | 7 |
A,1,16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,1,8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,1,4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,1,2 | 1,1,A1 | 13 |
|
|
|
|
|
|
|
|
|
|
|
|
| A,3,4 | 4,4,A4 | 20 |
|
|
|
|
|
|
|
|
|
|
|
|
| A,1,2,4 | 1,4,7 | 10 |
|
|
|
|
|
|
|
|
|
|
|
| A,5,8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,5,6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,7,8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,5,6,8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| A,1,4,8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
从上表的递归情况进行分析:
最小子数组里面已经比较得到了最大连续的子数组,比如(A,1,2) (A,3,4) (A,1,2,4)中已经获取到最大数组,其作为A1,8的子数组左半边已经获取到最大子数组(可能为(A1,4)跨越中点的,也可能其他半边),而(A,1,4,8)只需要再进行跨越中点的子数组获取最大就可以和前面已经得到的结果即(A1,4) (A,5,8)进行对比,然后再跟跨越8的中点的最大子数组对比,就能得到结果了
这样理解后,从正面也想通了分治策略用递归实现的原理。a,1,16-> (a,1,8) and (a,9,16) and (a 1,8,16)中取最大连续子数组,再进行递归
Java实现分治求解最大连续子数组:
public class MaxContinuousArray {
public static int[] getMaxConArray(int left,int right,int[] arr){
int mid = (left+right)/2;
if(left==right){
return new int[]{left,right,arr[left]};
}
int[] leftMaxValue=new int[2];
int[] rightMaxValue=new int[2];
int[] midMaxValue=new int[2];
leftMaxValue=getMaxConArray(left, mid, arr);
rightMaxValue=getMaxConArray(mid+1, right, arr);
midMaxValue=getMidConArray(left, right, mid, arr);
if(leftMaxValue[2]>rightMaxValue[2]&&leftMaxValue[2]>midMaxValue[2]){
return leftMaxValue;
}else{
if(rightMaxValue[2]>midMaxValue[2]){
return rightMaxValue;
}else{
return midMaxValue;
}
}
}
private static int[] getMidConArray(int left,int right,int mid,int[] arr){
int leftSubMaxValue=0;
int leftSubMaxInd=mid;
int leftSubSum=0;
int rightSubMaxValue=0;
int rightSubMaxInd=mid;
int rightSubSum=0;
for(int i=1;i<mid-left+1;i++){
leftSubSum+=arr[mid-i];
if(leftSubMaxValue<leftSubSum){
leftSubMaxValue=leftSubSum;
leftSubMaxInd=mid-i;
}
}
for(int i=1;i<right-mid+1;i++){
rightSubSum+=arr[mid+i];
if(rightSubMaxValue<rightSubSum){
rightSubMaxValue=rightSubSum;
rightSubMaxInd=mid+i;
}
}
return new int[]{leftSubMaxInd,rightSubMaxInd,leftSubMaxValue+rightSubMaxValue+arr[mid]};
}
}