数组子数组系列问题的总结


1)最大连续子数组和

     一个有N个元素的整型数组arr,有正有负,数组中连续一个或多个元素组成一个子数组,这个数组当然有很多子数组,求子数组之和的最大值。例如:[0,-2,3,5,-1,2]应返回9,[-9,-2,-3,-5,-3]应返回-2。

     对于O(N3)和O(N2)的解法就不再赘述,这里是分治法(NlogN)和O(N)的实时解法。

1.1分治法

   1: #include <iostream>
   2: #include <vector>
   3: using namespace std;
   4: int MaxSub(vector<int>::const_iterator &,
   5: vector<int>::const_iterator &);
   6: int Max3(int, int,int);
   7: int main(){
   8:     int Length,x,MaxSubsum;
   9:     vector<int> Arr;
  10:     cout<<"Input Length of the array:";
  11:     cin>>Length;
  12:     cout<<"Input the arry:";
  13:     for(int i=1;i<=Length;i++){
  14:        cin>>x;
  15:        Arr.push_back(x);
  16:     }
  17:     vector<int>::const_iterator beg=Arr.begin(),end=Arr.end()-1;
  18:     MaxSubsum=MaxSub(beg,end);
  19:     cout<<"Maximum Summation of subArry is from "
  20:         <<beg-Arr.begin()+1<<
  21:         " to "<<end-Arr.begin()+1<<":"<<endl<<MaxSubsum<<endl;
  22:     system("pause");
  23:     return 0;
  24: }
  25:  
  26: int MaxSub(vector<int>::const_iterator &beg,
  27:     vector<int>::const_iterator &end){
  28:     int MaxLeft,MaxRight,Max,MaxLeftRight;
  29:     vector<int>::const_iterator mid1,mid2,itr;
  30:     mid1=beg+(end-beg)/2;
  31:     mid2=mid1+1;
  32:     if (beg==end) return *beg;
  33:  
  34:     MaxLeft=MaxSub(beg,mid1);
  35:     MaxRight=MaxSub(mid2,end);
  36:     for(itr=beg,MaxLeftRight=0;itr!=end+1;itr++)
  37:         MaxLeftRight+=*itr;
  38:     Max=Max3(MaxLeft,MaxRight,MaxLeftRight);
  39:     if(Max==MaxLeft)
  40:     end=mid1;
  41:     else if(Max==MaxRight)
  42:     beg=mid2;
  43:  
  44:     return Max;
  45: }
  46:  
  47: int Max3(int a, int b,int c){
  48:     if(a>b) return a>c?a:c;
  49:     else return b>c?b:c;
  50: }
 
1.2 实时算法,时间复杂度复杂度O(N)
   1: #include <iostream>
   2: #include <vector>
   3: int main(){
   4:     int Length,x,MaxSubsum,CurrSubsum=0;
   5:     vector<int> Arr;
   6:     vector<int>::iterator beg,end;
   7:     cout<<"Input Length of the array:";
   8:     cin>>Length;
   9:     cout<<"Input the arry:";
  10:     for(int i=1;i<=Length;i++){
  11:        cin>>x;
  12:        Arr.push_back(x);
  13:     }
  14:     beg=Arr.begin(),end=Arr.end()-1;
  15:     MaxSubsum=Arr[0];
  16:     for(vector<int>::iterator itr=Arr.begin();itr!=Arr.end();itr++){
  17:         CurrSubsum+=*itr;
  18:         if(CurrSubsum<0){CurrSubsum=0;beg=itr+1;}
  19:         else if(CurrSubsum>MaxSubsum){MaxSubsum=CurrSubsum;end=itr;}
  20:     }
  21:     cout<<"Maximum Summation of subArry is from "<<beg-Arr.begin()+1<<
  22:         " to "<<end-Arr.begin()+1<<":"<<endl<<MaxSubsum<<endl;
  23:     system("pause");
  24:        return 0;
  25: }
       以上是两种较优的最大子数组和的算法,最小子数组和同理可求。
 
2)最小正子序列和

思路:(1)先求出数组的前缀数组之和,例如:2,-3,-3,7,5=>前缀数组和为2,-1,-4,3,8(它们的索引0 1 2 3 4)

(2)对前缀数组进行排序得到:-4,-1,2,3,8(即是这样的:(-4,3)  (1,1)  (2,0)  (3,3,)  (8,4) )

(3)则最小值一定是在:-4,1,2,3,8(结果一定在当前项减去前面一项,同时满足索引

大于前一项的索引)
 
   1: #include <iostream>
   2: #include <vector>
   3: #include <algorithm>
   4: using namespace std;
   5: #define MAX  1000
   6: class Item{
   7: public:
   8:     int Num;
   9:     int Order;
  10:     Item(): Num(0),Order(0){}
  11: };
  12: bool operator<(const Item &a,const Item &b){
  13:     return a.Order<b.Order;
  14: }
  15: int operator-(const Item& a,const Item& b){
  16:     return a.Num-b.Num;
  17: }
  18: bool comp(const Item &a,const Item& b){
  19:      return a.Num<b.Num;
  20: }
  21:  
  22: int main(){
  23:     int Length,x,MaxSubsum,CurrSubsum=0;
  24:     vector<int> Arr;
  25:     vector<Item> Sum;
  26:     Item item;
  27:     cout<<"Input Length of the array:";
  28:     cin>>Length;
  29:     cout<<"Input the arry:";
  30:     for(int i=0;i<Length;i++){
  31:        cin>>x;
  32:        Arr.push_back(x);
  33:        item.Num=item.Num+x;
  34:        item.Order=i;
  35:        Sum.push_back(item);
  36:     }
  37:     sort(Sum.begin(),Sum.end(),comp);
  38:     int minpositive=Sum[Length-1].Num>MAX?Sum[Length-1].Num:MAX;
  39:     for(vector<Item>::iterator itr=Sum.begin();itr!=Sum.end()-1;itr++)
  40:         if(*itr<*(itr+1)&&*(itr+1)-*itr>0&&*(itr+1)-*itr<minpositive)
  41:             minpositive=*(itr+1)-*itr;
  42:     cout<<"The minimum Positive Summation is:"<<minpositive<<endl;
  43:     system("pause");
  44: }
    最小负子序列和同理可求.算法复杂度O(N+NlogN)=O(NlogN).
 
3 最大子数组乘积:

     求最大连续子序列乘积与最大连续子序列和问题有所不同,因为其中有正有负还有可能有0。假设数组为a[],直接利用动归来求解,考虑到可能存在负数的情况,我们用Max[i]来表示以a[i]结尾的最大连续子序列的乘积值,用Min[i]表示以a[i]结尾的最小的连续子序列的乘积值,那么状态转移方程为:

       Max[i]=max{a[i], Max[i-1]*a[i], Min[i-1]*a[i]};
       Min[i]=min{a[i], Max[i-1]*a[i], Min[i-1]*a[i]};
      初始状态为Max[0]=Min[0]=a[0]。算法复杂度位O(N).
代码如下:
 1 double max3(double,double,double);
 2 double min3(double,double,double);
 3 double max3(double a,double b,double c){
 4     if(a>b) return a>c?a:c;
 5     else return b>c?b:c;
 6 }
 7 double min3(double a,double b,double c){
 8     if(a<b) return a<c?a:c;
 9     else return b<c?b:c;
10 }
11 
12 int main()
13 {
14    int n,j;
15    double MaxMupl;
16    double *Arr,*Max,*Min;
17    printf("Input the size of the array:");
18    scanf("%d",&n);
19    Arr=(double *)malloc(sizeof(double)*n);
20    Max=(double *)malloc(sizeof(double)*n);
21    Min=(double *)malloc(sizeof(double)*n);  
22    for ( j=0;j<n;j++)
23       scanf("%lf",Arr+j);
24    Max[0]=Min[0]=MaxMupl=Arr[0];
25    for (int i=1;i<n;i++){
26      Max[i]=max3(Arr[i],Max[i-1]*Arr[i],Min[i-1]*Arr[i]);
27      Min[i]=min3(Arr[i],Max[i-1]*Arr[i],Min[i-1]*Arr[i]);
28      if(Max[i]>MaxMupl) MaxMupl=Max[i];
29    }
30    if(MaxMupl>0){
31        if(MaxMupl==(int)MaxMupl) printf("%d",(int)MaxMupl);
32        else printf("%.2lf",MaxMupl);
33    }
34    else printf("-1\n");
35    system("pause");
36    free(Arr);
37    free(Max);
38    free(Min);
39    return 0;
40 } 

 

posted on 2014-01-05 22:23  Matteo  阅读(361)  评论(0)    收藏  举报

导航