最大连续子数组
题目描述
给定一个数组序列(如果数组全部是正数,最大子数组就是序列本身,所以这里假定序列中存在正数跟负数),找到数组中和最大的连续数组。
算法分析
从题目的描述中我们很容易想到的就是暴力破解,利用两层循环找出最大连续子数组,但是这样的算法复杂度是O(n^2)。这里考虑使用分治法的思想分析问题,找到时间复杂度更小的解决方法。
采用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组,也就是说找到子数组的中央位置,然后考虑求解两个子数组A[low,mid]和A[mid+1,high]。这里只要分为三种情况。
1、完全位于子数组A[low,mid]中,因此low<=i<=j<=mid。
2、完全位于子数组A[mid+1,high]中,因此mid<=i<=j<=high。
3、跨越了中点,因此low<=i<=mid<=j<=high。
跨越中点算法实现
C语言实现代码
typedef struct Index{
int indexL,indexR,sum;
}index;
index *cross_subarray(int *A,int low,int mid,int high){
int sumL=-10000,sumR=-10000,sum=0,i,j,indexL,indexR;
index *idx;
for(i=mid;i>=low;i--){
sum+=A[i];
if(sum>sumL){
sumL=sum;
indexL=i;
}
}
sum=0;
for(j=mid+1;j<=high;j++){
sum+=A[j];
if(sum>sumR){
sumR=sum;
indexR=j;
}
}
idx->indexL=indexL;
idx->indexR=indexR;
idx->sum=sumR+sumL;
return idx;
}
Java实现代码
public static index cross_sub(int A[],int low,int mid,int high){
index idx = new index();
int sumL=-10000,sumR=-10000,indexL=low,indexR=high,sum=0,i;
for(i=mid;i>=low;i--){
sum=sum+A[i];
if(sum>sumL){
sumL=sum;
indexL=i;
}
}
sum=0;
for(i=mid+1;i<=high;i++){
sum=sum+A[i];
if(sum>sumR){
sumR=sum;
indexR=i;
}
}
idx.setLeft(indexL);
idx.setRight(indexR);
idx.setSum(sumR+sumL);
return idx;
}
分治法完整代码实现
C语言
#include"stdio.h"
typedef struct Index{
int indexL;
int indexR;
int sum;
}index;
index *cross_subarray(int *A,int low,int mid,int high){
int sumL=-10000,sumR=-10000,sum=0,i,j,indexL,indexR;
index idx={0,0,0};
for(i=mid;i>=low;i--){
sum+=A[i];
if(sum>sumL){
sumL=sum;
indexL=i;
}
}
sum=0;
for(j=mid+1;j<=high;j++){
sum+=A[j];
if(sum>sumR){
sumR=sum;
indexR=j;
}
}
idx.indexL=indexL;
idx.indexR=indexR;
idx.sum=sumR+sumL;
return &idx;
}
index *find_subarray(int *A,int low,int high){
int mid;
index *idx1,*idx2,*idx3;
index idx4={0,0,0};
if(low == high){
idx4.indexL=low;
idx4.indexR=high;
idx4.sum=A[low];
return &idx4;
}else{
mid=(low+high)/2;
idx1=find_subarray(A,low,mid);
idx2=find_subarray(A,mid+1,high);
idx3=cross_subarray(A,low,mid,high);
if(idx1->sum>=idx2->sum && idx1->sum>=idx3->sum){
return idx1;
}else if(idx2->sum>=idx1->sum && idx2->sum>=idx3->sum){
return idx2;
}else{
return idx3;
}
}
}
int main(){
index *idx;
int A[]={-9,8,-7,6,3,-2,1};
idx = find_subarray(A,0,6);
printf("%d,%d,%d\n",idx->indexL,idx->indexR,idx->sum);
return 0;
}
Java代码实现
public class cross_subarray {
public static index cross_sub(int A[],int low,int mid,int high){
index idx = new index();
int sumL=-10000,sumR=-10000,indexL=low,indexR=high,sum=0,i;
for(i=mid;i>=low;i--){
sum=sum+A[i];
if(sum>sumL){
sumL=sum;
indexL=i;
}
}
sum=0;
for(i=mid+1;i<=high;i++){
sum=sum+A[i];
if(sum>sumR){
sumR=sum;
indexR=i;
}
}
idx.setLeft(indexL);
idx.setRight(indexR);
idx.setSum(sumR+sumL);
return idx;
}
public static index find_subarray(int A[],int low,int high){
index idx = new index(),
idx1 = new index(),
idx2 = new index(),
idx3 = new index();
if(low == high){
idx.setLeft(low);
idx.setRight(high);
idx.setSum(A[low]);
return idx;
}else{
int mid = (low+high)/2;
idx1 = find_subarray(A,low,mid);
idx2 = find_subarray(A,mid+1,high);
idx3 = cross_sub(A,low,mid,high);
if(idx1.getSum()>=idx2.getSum() && idx1.getSum()>=idx3.getSum()){
return idx1;
}else if(idx2.getSum()>=idx1.getSum() && idx2.getSum()>=idx3.getSum()){
return idx2;
}else{
return idx3;
}
}
}
public static void main(String[] args){
int A[]={-9,8,-7,6,3,-2,1};
index idx = find_subarray(A,0,6);
System.out.println(idx.left+","+idx.right+","+idx.sum);
}
}
算法时间复杂度分析
利用递归式分析算法的时间复杂度:
首先,求跨越中点算法的时间复杂度两个for循环O(n),利用递归拆分数组的算法时间复杂度为O(nlg(n))。所以时间复杂度为(O(n)+O(nlg(n)))。