【算法学习笔记】19.算法设计初步 最大子列和问题的几种方法
生活随笔
收集整理的這篇文章主要介紹了
【算法学习笔记】19.算法设计初步 最大子列和问题的几种方法
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
第一種就是純粹的暴力枚舉起始、終點。 O(n^3)
第二種在第一種的基礎(chǔ)上先進行初始化,將以第一個元素為起點,所有元素為終點的所有子列和存儲在S數(shù)組中,所以在第三層循環(huán)中計算子列和是直接用S[j]-S[i-1]即可,這是利用了空間去換時間。O(n^2)
第三種也是O(n^2),但是在第二種的基礎(chǔ)上,要先算出非負數(shù)所在的下標從而減少計算和的次數(shù),但是效果并不好。
//算法3 O(n^2) //主要是想算出正數(shù)的地方 從而減少算和的次數(shù),但是需要先找出所有的正數(shù)int n=0,seq[Max_N]={0};//1 for positive or 0 and 0 for negative int begin=0,end=0; long max_sum = NULL; int len = 0; int pos_list[Max_N]={0};void getMaxSubSeq(){if(len==0){//如果全是負數(shù)則返回0max_sum=0;return;}else if(len==1){//如果只有一個非負數(shù) 返回的就是它max_sum=seq[pos_list[0]];return;}else{//否則我們要對每對兒非負數(shù)下標進行計算子列和for (int j = 0; j<len; j++) {//j是非負數(shù)下標1long sum = 0;int h = 0;for (int k = j+1; k<=len; k++) {//k是非負數(shù)下標2//下面的for可以改寫成S[j]-S[i]的形式從而降低至S[j]-S[i]for (int t=pos_list[h]+(h==0?0:1);t<=pos_list[k] ; t++) {sum += seq[t];}//printf("%d\n",int(sum));h=k;if (max_sum == NULL || max_sum<sum) {max_sum = sum;}}}}}int main(int argc, const char * argv[]) {scanf("%d",&n);//input seqfor (int i = 0; i<n; i++) {scanf("%d",&seq[i]);if(seq[i]>=0){pos_list[len]=i;//把非負數(shù)的位置都記下來len++;//len是非負數(shù)的個數(shù)}}getMaxSubSeq();cout<<(max_sum)<<endl;return 0; }第四種 利用分治法的思想,先算左面,再算右面(都是遞歸),再從中間開始向兩邊延伸。O(nlgn) //算法4 //分治法 O(nlgn) //此時計算的是A[m,n)的范圍內(nèi)的最大子序列和 int getMaxSumOfSubSeq(int* A,int x,int y){//遞歸邊界if(y-x==1) return A[x];//分治第一步,劃分(確定子問題)int middle = x+(y-x)/2;//此處不用(x+y)/2的原因是想要使middle更加接近左端點//分治第二步 遞歸求解 //利用了>?運算符取兩者中較大的int maxOfTwoSides = getMaxSumOfSubSeq(A, x, middle) >?getMaxSumOfSubSeq(A,middle , y);//分治第三步 合并 求最終解int v = 0;//此處v是用來暫時儲存連續(xù)從中段開始向兩邊延伸的連續(xù)和int L=[middle-1],R=A[middle];//從中間開始for (int i=middle-1; i>=x; i--)L >?= (v+=A[i]);v=0;//重復(fù)利用臨時變量for (int i=middle; i<y; i++)//注意不要包括yR >?= (v+=A[i]);return maxOfTwoSides >? (L+R); }
第五種,
思路主要是這樣的。
在我們用第二種思路時,第二層循環(huán)內(nèi)部要進行比較S[j]-S[i-1]和當前最大和誰大,其實在這個時候,j是一定的,比誰大的本質(zhì)就是找S[i-1]最小,所以我們不如去維護目前遇到過的最小的S.?
int getMSoSS(int* A,int len){int index_ofMinS = 0;int S[Max_N];S[0]=A[0];//第一步 先算出最小的S在哪里取得//實驗表明,如果S[len-1]是最小的 必須用第二小的才行 所以就不算len-1了for(int i =1;i<len;i++){S[i] = S[i-1]+A[i];if(i<len-1 and S[i]<S[index_ofMinS]) index_ofMinS=i;}//此時已經(jīng)確定了i-1=index....int max_sum=S[0];//從此下標之后開始計算~for(int j=index_ofMinS+1;j<len;j++){//gcc 應(yīng)該是可以寫成 max_sum >?= S[j]-S[index_ofMinS];的呀 奇怪~max_sum = max(max_sum , (S[j]-S[index_ofMinS]));}return max_sum; }第六種的偽代碼描述:在線處理算法 最核心的想法就是 ?當前和如果是負數(shù)就不要進行下去 因為無論后面是什么,都相當于在做減法,不會比最大和高。
厲害啦,是在線算法,在線算法就是說,任何時候停止輸入,得到的都是當前的正確結(jié)果,所以應(yīng)該是線性的O(n)算法。
轉(zhuǎn)載于:https://www.cnblogs.com/yuchenlin/p/4379252.html
總結(jié)
以上是生活随笔為你收集整理的【算法学习笔记】19.算法设计初步 最大子列和问题的几种方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android studio 开发中
- 下一篇: 【SICP练习】79 练习2.51