日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

四种解法——求子序列的最大连续子序和(普通解法、求和解法、分治法、O(n)级解法)(面试经典题)

發布時間:2024/2/28 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 四种解法——求子序列的最大连续子序和(普通解法、求和解法、分治法、O(n)级解法)(面试经典题) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

勵志用少的代碼做高效表達


在這四種解法里,解法一是通法,可以學到規律和知識,做基礎之用;解法二在解法一的基礎上做改進,鍛煉思維;解法三則是大名鼎鼎的分治法,涉及到遞歸的知識,算是“高效算法設計”的基礎;解法四以O(n)的復雜度解出最大連續子序和,一個字,神奇。四種解法循序漸進,效率逐步提高,精妙至極。建議初學者每種都要掌握。


解法一:最普通的解法,定義i循環,代表數組從0到n-1的值,定義j循環,代表從a[i]開始,到a[j]結束。 定義k循環,將從a[i]至a[j]所有的數相加,最后求出最大子序列和。
時間復雜度:O(n^3)

#include<bits/stdc++.h> using namespace std; int main() {int n; cin>>n; int a[n];for(int i = 0; i < n; i++) cin>>a[i];int sum = a[0]; //不能等于0,因為可能是全負序列 int temp = 0;for(int i = 0; i < n; i++) for(int j = i; j < n; j++) //二重循環, 從i截止到j遍歷 for(int k = i; k <=j; k++) //i-j序列的區間和。 temp += a[k]; sum = max(sum, temp);}cout << sum << endl;return 0; }

解法二:定義數列S[n],S[i]=a[0]+a[1]+...+a[i]。 若j>i,則S[j]-S[i-1]=a[j]+a[j-1]+...+a[i]。也就是說,嵌套兩個for循環, 一個為i,一個為j,就可以表示出任何子序列的和,最后作比較即可。
時間復雜度:O(n^2)

#include<bits/stdc++.h> using namespace std; int main() {int n; cin>>n; int a[n];for(int i = 0; i < n; i++) cin>>a[i];int S[n+1]; S[0]=0;for(int i = 1; i <= n; i++) S[i] = a[i] + S[i-1];int best = 0;for(int i = 1; i <= n; i++) for(int j = i; j <= n; j++) best = max(best, S[j]-S[i-1]);return 0;}

解法三:分治法,顧名思義,分而治之。

分治算法一般分為以下3個步驟:
一、劃分問題:把問題的實例劃分成子問題。
二、遞歸求解:遞歸解決子問題。
三、合并問題:合并子問題的解得到原問題的解。

最大連續和的分治算法:
1、把序列分成元素個數盡量相等的兩半
2、分別求出完全位于左半或者完全位于右半的最佳序列
3、求出起點位于左半、終點位于右半的最大連續和序列,并和子問題的最優解比較。

涉及到遞歸的代碼都比較復雜,但如果實在理解不了,就背下來把,想想小時候背的古詩,就算死記硬背下來,隨著時間的推移,也會慢慢懂得其含義的。

時間復雜度:O(nlogn) (這種級別的時間復雜度,一般就可以應付絕大多數的競賽了)

#include<bits/stdc++.h> using namespace std; int a[10005];int longsub(int *a, int l, int r) { //返回數組在左閉右開區間[x,y)中最大連續和//為什么不返回a[r]呢? 因為該區間是左閉右開區間 if(r-l == 1) return a[l]; //只有一個元素直接返回 int mid = l + (r-l)/2; //分治第一步:劃分成[l,m)和[m,r) int maxs = max(longsub(a,l,mid), longsub(a,mid,r)); //分治第二步:遞歸求解int v, Lmax, Rmax;v=0; Lmax = a[mid-1]; //分治第三步:合并(1)——從分界點開始往左的最大連續和lfor(int i=mid-1; i>=l; i--) Lmax=max(Lmax, v+=a[i]);v=0; Rmax=a[mid]; //分治第三步:合并(2)——從分界點開始往右的最大連續和r for(int i=mid; i<r; i++) Rmax=max(Rmax, v+=a[i]); return max(maxs, Lmax+Rmax); }int main() {int n; cin>>n;for(int i = 0; i < n; i++) cin>>a[i];cout << longsub(a, 0, n); return 0;}

解法四:
很特殊的解法,核心思想:當遍歷到第i個元素時,判斷在它前面的連續子序列和是否大于0,如果大于0,則以位置i結尾的最大連續子序列和為元素i和前門的連續子序列和相加;否則,則以位置i結尾的最大連續子序列和為元素i。
時間復雜度:O(n)

#include<iostream> using namespace std; int main() {int n; cin>>n; int a[n];for(int i = 0; i < n; i++) cin>>a[i];int maxsum, maxhere;maxsum = maxhere = a[0]; //初始化最大和為a[0]for(int i = 1; i < n; i++) {if(maxhere <= 0) maxhere = a[i]; //若前面位置連續子序列和小于0,則以當前位置開始 else maxhere += a[i]; //若大于零,則加入if(maxhere > maxsum) maxsum = maxhere; //更新 } cout << maxsum << endl; return 0; }

如果這篇文章對你產生了幫助,就請給博主一個贊吧!大家的點贊是我創作的最大動力!

總結

以上是生活随笔為你收集整理的四种解法——求子序列的最大连续子序和(普通解法、求和解法、分治法、O(n)级解法)(面试经典题)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。