以最大連續和為例的演算法分析
阿新 • • 發佈:2019-01-26
學習劉汝佳老師的《演算法競賽》總結
最大連續和問題
給出一個長度為n的序列A
一.使用列舉,程式如下:
tot = 0;
best = A[1]; //初始最大值
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++) { //檢查連續子序列A[i],……,A[j]
int sum = 0;
for (int k = i; k <= j; k++) {
sum += A[k]; //累加元素和
tot++;
}
if (sum > best)
best = sum; //更新最大值
}
設輸入規模為n時,加法操作的次數為T(n),則
用一個記號來表示:T(n)=O(n
二.下面試著優化一下這個演算法。
設S
S[0] = 0;
for (int i = 1; i <= n; i++)
S[i] = S[i - 1] + A[i]; //遞推字首和S
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
best = max(best, S[j] - S[i - 1]); //更新最大值
類似的方法可以分析出:
時間複雜度是O(n
三.分治法
分治演算法一般分為以下三個步驟:
劃分問題
遞迴求解:遞迴解決子問題;
合併問題:合併子問題的解得到原問題的解。
在本例中,”劃分“就是把序列儘量分成元素個數相等的兩半;”遞迴求解“就是分別求出完全位於左半和完全位於右半的最佳序列;”合併“就是求出起點位於左半,終點位於右半的最大連續和序列,並和子問題的最優解比較。
int maxsum(int *A, int x, int y) { //返回陣列在左閉右開區間[x,y)中的最大連續和
int V, L, R, maxs;
if (y - x == 1)
return A[x];
int m = x + (y - x) / 2; //分治第一步:劃分成[x,m)和[m,y)
maxs = max(maxsum(A, x, m), maxsum(A, m, y)); //分治第二步:遞迴求解
V = 0;
L = A[m - 1]; //分治第三步:合併(1)——從分界點開始往左的最大連續和L
for (int i = m - 1; i >= x; i--)
L = max(L, V += A[i]);
V = 0;
R = A[m]; //分治第三步:合併(2)——從分界點開始往右的最大連續和R
for (int i = m; i <= y; i++)
R = max(R, V += A[i]);
return max(maxs, L + R); //把子問題的解與L + R比較
}
遞迴方程T(n)=2T(n/2)+O(n),T(1)=1,解為T(n)=O(n log n).
四.演算法分析結果
表-運算量隨著規模的變化
運算量 | 最大規模 | 速度擴大兩倍後 |
---|---|---|
n! | 11 | 11 |
2 |
26 | 27 |
n |
464 | 584 |
n |
10000 | 14142 |
nlog |
4.5x10 |
8.6x10 |
n | 100000000 | 200000000 |
借鑑此表,在演算法競賽中,一個指明n