方法一:
暴力求解html
#include<stdio.h> #include<stdlib.h> #include<limits.h> int maxsubset(int *a,int len){ int summax=INT_MIN; int i,j,k; for(i=0;i<len;i++) for(j=i;j<len;j++){ int temp=0; for(k=i;k<=j;k++) temp+=a[k]; if(temp > summax) summax=temp; } return summax; } int main(){ int a[]={3,-1,2,5,-3,4,-6,-7,1,8,-3,5,9}; printf("the maxsubset:%d\n",maxsubset(a,13)); return 0; }
方法二:分治求解算法
#include<stdio.h> #include<stdlib.h> #include<limits.h> int cross_middle(int *a,int l,int m,int r){ int i, sum=0, l_max=INT_MIN, r_max=INT_MIN; for(i=m;i>=l;i--){ sum+=a[i]; if(sum > l_max) l_max=sum; } sum=0; for(i=m+1;i<=r;i++){//最先i=m,出現BUG sum+=a[i]; if(sum>r_max) r_max=sum; } return (l_max+r_max); } int maxsubset(int *a,int l,int r){ if(l == r) return a[l]; //if(l>r) return 0; int m=(l+r)/2, l_max=INT_MIN, r_max=INT_MIN, c_max=INT_MIN; l_max=maxsubset(a,l,m); r_max=maxsubset(a,m+1,r); c_max=cross_middle(a,l,m,r); if(l_max >= r_max&&l_max >= c_max) return l_max; else if(r_max >= l_max&&r_max >= c_max) return r_max; else return c_max; } int main(){ int a[]={3,-1,2,5,-3,4,-6,-7,1,8,-3,5,9}; printf("the maxsubset:%d\n",maxsubset(a,0,12)); return 0; }
方法三 線性時間實現:數組
#include<stdio.h> #include<stdlib.h> #include<limits.h> int maxsubset(int *a,int l,int r){ int i, temp=0, summax=INT_MIN; for(i=l;i<=r;i++){ temp+=a[i]; if(temp > summax) summax=temp; if(temp < 0) temp=0; } return summax; } int main(){ int a[]={3,-1,2,5,-3,4,-6,-7,1,8,-3,5,9}; printf("the maxsubset:%d\n",maxsubset(a,0,12)); return 0; }
方法三線性時間實現基於這樣的思路:
若是a[1..j]已經獲得了其最大子數組,那麼a[1..j+1]最大子數組只能是兩種狀況
(1)a[1..j+1]的最大子數組就是a[1..j];
(2)a[1..j+1]的最大子數組是a[i..j+1],1<=i<=j;
那麼,如何求得所謂的(2)中的a[i..j+1]呢?
首先須要認可這樣的事實,若是一個數組a[p..r]求和獲得負值,那麼數組a[p..r+1]的最大子數組確定不會是a[p..r+1],由於a[p..r]+a[r+1]<a[r+1].
在以上程序中,咱們用temp存儲所謂的a[p..r],只要a[p..r]的求和是負值,那麼從下一個a[r+1]值開始,temp從新從零開始求和,只要temp > summax,就更新summax,這樣,咱們一次遍歷後,就能獲得最大的summax,接下來,咱們證實該算法是有效的
證實:
對於全部數組元素,這樣的元素對數組進行劃分,若是加上該元素以前temp>0且temp+a[i]<0,那麼該元素a[i]是一個邊界,這樣,數組會造成好多段,每段結束元素都知足temp>0且temp+a[i]<0.因此咱們能獲得多個劃分塊a[p..q],每一個劃分快的和是負值,劃分塊有這樣的性質,對任意p<=i<q,顯然,sum(a[p..i])>=0且sum(a[i..q])<0;
咱們要證實post
(1)最大子數組必定在劃分塊以內
證實:
根據劃分快性質,容易證實,只要子數組橫跨多個劃分快,其求和值一定小於某個單獨的劃 分快中的數組求和。code
(2)必定存在首元素以劃分塊的首元素開始的最大子數組。htm
證實:
對於某個劃分快a[p..q],假設存在a[i..j],其中p<i<=j<q,那麼根據劃分塊性質,a[p..i-1]+a[i..j]>=a[i..j]一定成立,得證。
因此,經歷一次遍歷,對於每一個劃分塊,從首元素開始求和,獲得最大值更新summax,必定可以獲得最大子數組的值。blog
//-------------------------------------------------------------------------
求數組的最大子數組的積怎麼求呢?
解決方法是保存最大負值和最大正值,實現以下:get
#include<stdio.h> #include<stdlib.h> #include<limits.h> int sunsetmax_mul(int *a,int l,int r){ int i,temp, nmax=0,//negtive max pmax=0,//positive max _max=a[l]; nmax=(_max<0 ? _max : 0); pmax=(_max>0 ? _max : 0); for(i=l+1;i<=r;i++){ if(a[i] < 0){ temp=pmax; pmax=nmax==0 ? 0 : nmax*a[i]; nmax=temp==0 ?a[i]: temp*a[i]; } else if(a[i] > 0){ pmax=pmax==0 ? a[i]: pmax*a[i]; nmax=nmax==0 ? 0 : nmax*a[i]; } else { pmax=nmax=0; } if(pmax > _max) _max=pmax; } return _max; } int main(){ int a[]={-2,2,2,-5,2/*,5,-3,4,-6,-7,1,8,-3,5,9*/}; printf("max mul subset result is %d\n",sunsetmax_mul(a,0,4)); }
其餘思想:
另外一種思路(包括最大子數組的積)it