您的位置:首页 > 其它

最大子数组问题

2016-04-28 21:54 281 查看
问题的意思也就是,求出一个数组中连续的几个元素的最大值。

思路:先用一种分治的方法来解。 时间复杂度为O(nlgn)

将求A[i,...,j]上最大子数组和为问题 分解成以下三种情况,令mid=(i+j)/2

第一,求出A[i,...,mid]上的最大子数组和

第二,求出A[mid+1,...,j]上的最大子数组和

第三,结果跨跃mid,也就是说,子数组必将是A[...,mid,...]的形式

很明显,原问题的求解答案必将是以上三种情况中的一种,我们来看第三种,因为它可以在O(n)的时间上求出

因为结果跨越了mid,那么可以将子数组分为两段,mid左边和mid右边,对于左右边,只要依次判断加了当前点之后,sum的值有没有比原来大,最后将左右两边最大值相加。

#include <iostream>
using namespace std;

#define MIN -1000

int crossing(int A[],int low,int mid,int high){
int sum = 0;
int left_sum = MIN;
for(int i=mid;i>=low;i--){
sum = sum + A[i];
if(sum > left_sum){
left_sum = sum;
}
}
sum = 0;
int right_sum = MIN;
for(int j=mid+1;j<=high;j++){
sum = sum + A[j];
if(sum > right_sum)
right_sum = sum;
}
return left_sum + right_sum;
}

int maximum(int A[],int low,int high){
if(low == high){
return A[low];
}
else{
int mid = (low + high)/2;
int maxleft = maximum(A,low,mid);
int maxright = maximum(A,mid+1,high);
int maxcrossing = crossing(A,low,mid,high);
if(maxleft>=maxright && maxleft>=maxcrossing)
return maxleft;
else if(maxright>=maxleft && maxright>= maxcrossing)
return maxright;
else
return maxcrossing;
}
}

int main(){
int A[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int length = sizeof(A)/sizeof(int);
int result = maximum(A,0,length-1);
cout<<result<<endl;
return 0;
}

下面介绍一种时间复杂度更小的算法,在O(n)的时间内实现

用res[i]表示以第i个元素结尾的最大子数组之和,很明显,res[i] = max(res[i-1]+a[i],a[i]) ,其实只要判断res[i-1]是否大于0

然后每增加一个元素,看一下子数组之和是否有增加 即可。这里只需保存前一个res[i-1]的值

#include <iostream>
using namespace std;

#define MIN -1000

int main(){
int A[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int length = sizeof(A)/sizeof(int);
int ans = A[0];
int sum = A[0];
for(int i=1;i<length;i++){
if( sum > 0)
sum += A[i];
else
sum = A[i];
if(sum > ans)
ans = sum;
}
cout<<ans<<endl;
return 0;
}

如果要求出 最大子数组 的前后位置,则应用left,right作标记

#include <iostream>
using namespace std;

#define MIN -1000

int main(){
int A[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int length = sizeof(A)/sizeof(int);
int ans = A[0];
int sum = A[0];
int left = 0,right = 0;
for(int i=1;i<length;i++){
if( sum > 0){
sum += A[i];
}
else{
sum = A[i];
left = right = i;
}
if(sum > ans){
right = i;
ans = sum;
}
}
cout<<"第"<<left+1<<"个元素到第"<<right+1<<"个元素之和最大"<<endl;
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: