最大連續和的方法總結

2021-06-26 15:39:40 字數 4936 閱讀 4834

最大連續和的方法總結

第一種:暴力。複雜度o(n^3)。用兩個迴圈列舉起點和終點,然後中間再放乙個迴圈,計算這個起點到終點的連續和。

偽**:
max = -inf;

s[maxn];

for i in range(1, len):

for(j in range(i, len)):

sum = 0;

for (k in range(i, j)):

sum += s[k];

else:

max = max(max, sum);

else:;

else:

return max;

第二種:預處理 + 暴力列舉起點終點。複雜度o(n^2)。和第乙個類似,只是一開始用sum[i],來儲存從1到i的連續和。這樣就可以去掉第三層的迴圈,直接用sum[end] - sum[begin]得到。

偽**:
max = -inf;

s[maxn], sum[maxn];

sum[0] = 0;

for i int range(1, len):

sum[i] = sum[i - 1] + s[i];

else:;

for i in range(1, len):

for j int range(i, len):

max = max(max, sum[j] - sum[i - 1]);

else:;

else:

return max;

第三種:分治法, 複雜度o(n*log(n))。思路是將長度為len的序列劃分左右兩個左閉右開的區間[l,m) [m, r),然後遞迴求出左邊的區間的最大連續和,再求出右邊的最大連續和,最後在求出跨中點m的最大連續和,這個區間的最大連續和就在這三者之中。將每個區間都劃分成子問區間,直到區間只有乙個數的時候停止。注意:兩個區間不能同時擁有同乙個元素,這樣在後面的區間再劃分的時候會出錯(劃分成單個元素區間的時候會發現每個元素都多了乙個),這也是要左閉右開區間的原因。

偽**:
l = 1;

r = len + 1;

function maxsum (l, r)

if r - l == 1: return s[l];

m = (l + r) / 2;

//左子區間

maxlp = maxsum(l, m);

//右子區間

maxrp = maxsum(m, r);

max = max(maxlp, maxrp);

//中間的跨越中點m的區間

sumlp = s[m - 1];

sum = 0;

for i in range(m - 1, l)://i--

sum += s[i];

maxlp = max(maxlp, sum);

else:;

sumrp = s[m];

sum = 0;

for i in range(m, r - 1)://i++

sum += s[i];

maxrp = max(maxrp, sum);

else:;

return max(max, maxrp + maxlp);

end function

第四種:累積遍歷演算法(1),複雜度o(n).從左到右用乙個sum變數累計,當sum<0的時候就令sum = 0,再去加上後面的數,並且在這個遍歷的過程中記錄下sum的最大值。換句話說:用這個sum將這個序列分段,如果前面的連續和比0還小的話,那麼加上後面的數倒還沒有後面的數自己作為開頭的連續和大,所以就讓sum = 0.這樣才可能產生比前面的連續和更大的值。

偽**:
s[maxn];

max = sum = s[1];

for i in range(2, len):

if sum < 0:

sum = s[i];

else:

sum += s[i];

max = max (max, sum);

else: return max;

第五種:累積遍歷演算法(2),複雜度o(n).同樣也是用乙個變數sum來累計,只是這裡用乙個minpart來儲存前面從1開始的最小的連續和。因為這個序列的所有值的和是確定的,那麼只要取得了前面的最小連續和,因為總值是固定的,後面的就是最大的連續和,也就是遍歷過程中sum - minpart的最大值。

偽**;
s[maxn];

minpart = sum = 0;//注意開頭可能是正數

max = s[1];

for in range(1, len):

sum += s[i];

max = max (sum - minpart);

minpart = min (minpart, sum);

else: return max;

第六種:動態規劃,複雜度o(n)。和第四種的想法是類似的,只是這裡是開乙個sum[maxn]的陣列。狀態轉移方程:sum[i] = max(sum[i - 1] + s[i], s[i]);

偽**:
sum[maxn],s[maxn];

max = sum[1] = s[1];//只有乙個數的情況下只能取這個數

for in range(2, len):

sum[i] = max (sum[i - 1] + s[i], s[i])

max = max (max, sum[i]);

else: return max;

接下來是uva507的題目的四種解法,因為前兩種比較簡單而且放在這題會超時就不寫了。這題需要給出上下界的。

分治法

#include

#include

#include

using

namespace

std;

const

int maxn = 2e4 + 5;

int n, s[maxn];

struct ans

ans (int v, int l , int r) : v(v), l(l), r(r){}

void

set (int v, int l, int r)

};ans maxsum (int l, int r)

ans lp(s[m - 1], m - 1, m - 1), rp(s[m], m, m);

int tmp = 0;

for (int i = m - 1; i >= l; i--)

tmp = 0;

for (int i = m; i < r; i++)

ans center(lp.v + rp.v, lp.l, rp.r);

if (center.v > max_sum.v)

max_sum = center;

else

if (center.v == max_sum.v)

return max_sum;

}int main ()

return

0;

}

累計遍曆法(1):
#include

#include

#include

using

namespace

std;

const

int maxn = 2e4 + 5;

int n, s[maxn];

int solve (int& l, int& r) else

sum += s[i];

if (sum > max_num) else

if (sum == max_num) }}

return max_num;

}int main ()

return

0;

}

累積遍曆法(2):
#include

#include

#include

using

namespace

std;

const

int maxn = 2e4 + 5;

int n, s[maxn];

int solve (int& l, int& r) else

if (sum - min_sum == max_sum) }}

if (sum < min_sum)

}return max_sum;

}int main ()

return

0;

}

動態規劃:
#include

#include

#include

using

namespace

std;

const

int maxn = 2e4 + 5;

int n, s[maxn], sum[maxn];

int solve (int& l, int& r) else

sum[i] = sum[i - 1] + s[i];

//max

if (max_sum <= sum[i]) else

if (max_sum == sum[i] && (i + 1 - tmp > r - l)) }}

return max_sum;

}int main ()

return

0;

}

感謝gg大神:參考部落格

最大連續和

這個問題對我來說還挺難的,當初做dp時水過去了,但沒徹底理解,這次打算好好分析一下,爭取徹底搞懂。首先,像 1 1 2 2 3 3 4 4 5 5這樣的數列,想要找連續最大和,可以有很多種方法,從最慢的列舉o n 3 到最快的動態規劃o n 毫無疑問,我們要選擇複雜度低的演算法。所以我這裡就只分析兩...

最大連續和

求陣列中數的最大連續和,如 1,1,1,1,1 最大連續和為3 一 動態規劃 當我們從頭到尾遍歷這個陣列的時候,對於陣列裡的乙個整數,它有幾種選擇呢?它只有兩種選擇 1 加入之前的subarray 2.自己另起乙個subarray。那什麼時候會出現這兩種情況呢?設狀態為f j 表示以s j 結尾的最...

最大連續和

給出乙個長度為n的序列a1,a2,an,求最大連續和 使用列舉 時間複雜度o n 3 best a 1 初始最大值 for int i 1 i n i 設si a1 a2 ai,則ai ai 1 aj sj si 1 連續子串行的和等於兩個字首之差 時間複雜度o n 2 s 0 0 for int ...