四种解法——求子序列的最大连续子序和(普通解法、求和解法、分治法、O(n)级解法)(面试经典题)
勵志用少的代碼做高效表達
在這四種解法里,解法一是通法,可以學到規律和知識,做基礎之用;解法二在解法一的基礎上做改進,鍛煉思維;解法三則是大名鼎鼎的分治法,涉及到遞歸的知識,算是“高效算法設計”的基礎;解法四以O(n)的復雜度解出最大連續子序和,一個字,神奇。四種解法循序漸進,效率逐步提高,精妙至極。建議初學者每種都要掌握。
解法一:最普通的解法,定義i循環,代表數組從0到n-1的值,定義j循環,代表從a[i]開始,到a[j]結束。 定義k循環,將從a[i]至a[j]所有的數相加,最后求出最大子序列和。
時間復雜度:O(n^3)
解法二:定義數列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)
解法三:分治法,顧名思義,分而治之。
分治算法一般分為以下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)
如果這篇文章對你產生了幫助,就請給博主一個贊吧!大家的點贊是我創作的最大動力!
總結
以上是生活随笔為你收集整理的四种解法——求子序列的最大连续子序和(普通解法、求和解法、分治法、O(n)级解法)(面试经典题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 判断一个数是否是素数,为什么只要除到根号
- 下一篇: 14行代码AC_SCU 4440 Rec