数组子数组系列问题的总结
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 }
浙公网安备 33010602011771号