求最大欄位和

2022-08-10 16:45:12 字數 3033 閱讀 8371

最大子串行和問題乃經典演算法問題之一,很多教科書和技術文章都對此有詳述,博主重新整理一遍乃是為了消化和日後翻閱,不喜勿噴。

問題描述

給定乙個整數陣列,求出這組數字子串行和的最大值(為簡單起見,若陣列中所有數字都為負數,則返回0)。例如:

序列:-2 11 -4 13 -5 -2,則最大子串行和為20。

序列:-6 2 4 -7 5 3 2 -1 6 -9 10 -2,則最大子串行和為16。

演算法一

1 //窮舉法,所有的組合都加一遍,得到最大值

2 int getmaxsubsequencesum1(int array)

3 15 }

16 return maxsum;

17 }

這是乙個o(n3)的演算法,演算法本身很容易理解,而且很直觀的感覺做了很多無用操作。例如:i = 0, j = 3時,會計算a[0] + a[1] +…+ a[3];而當i = 0, j = 4時候又會計算a[0] + a[1] +…a[4]。演算法二會對此做一改進。(有句「格言」:計算任何事情不要超過一次。)

演算法二

1 int getmaxsubsequencesum2(int array)

2 13 }

14 return maxsum;

15 }

比演算法一少了一層for迴圈,so,複雜度也降為o(n2)。在日常工作中,做到這步我就滿足了,幾乎不會去想是否還有(時間上)更優的方法。

演算法三

1 //分治策略(divide-and-conquer)

2 int getmaxsubsequencesum3(int array, int left, int right)

3 19

20 //求出以右邊對後乙個數字結尾的序列最大值

21 int maxrightbordersum = 0, rightbordersum = 0;

22 for (int j = center + 1; j <= right; j++)

23

28 29 return math.max(math.max(maxleftsum, maxrightsum), maxleftbordersum + maxrightbordersum);

30 }

所謂分治策略,將大的問題分成大致相等的若干子問題,對它們求解並合併為最終解,依靠的即是遞迴演算法。具體到上述演算法,複雜度為o(nlogn)(猜測nlogn中的係數n乃是第8、9行兩次遞迴運算帶出來的)。分析演算法最讓人困惑的大概就是對數的出現。除分治演算法外,可將對數常出現的規律概括為以下一般法則:如果乙個演算法用常數時間(o(1))將問題的大小削減為其一部分(通常是二分之一),那麼該演算法的複雜度就是o(logn)。另一方面,如果使用常數時間只是把問題減少乙個常數(如將問題減少1),那麼這種演算法就是o(n)的。那麼,是否還有更優的(時間上)演算法呢?

演算法四

1 int getmaxsubsequencesum4(int array)

2 12 return maxsum;

13 }

很容易理解上述**的時間複雜度是o(n),但是要是弄明白為什麼正確就比較費力了。其實這個是演算法二的乙個改進。分析的時候也是i代表當前序列的起點,j代表當前序列的終點。如果我們不需要知道最佳子串行的位置,那麼i就可以優化掉。

重點的乙個思想是:如果

a[i]

是負數那麼它不可能代表最有序列的起點,因為任何包含

a[i]

的作為起點的子串行都可以通過用

a[i+1]

作為起點來改進。類似的有,任何的負的子串行不可能是最優子串行的字首。例如說,迴圈中我們檢測到從

a[i]

到a[j]

的子串行是負數,那麼我們就可以推進i。

關鍵的結論是我們不僅可以把

i推進到

i+1,而且我們實際可以把它一直推進到

j+1(j是使得從下標i開始成為負數的第乙個下標)

。舉例來說,令p是i+1到j之間的任何乙個下標,由於前面假設了a[i]+…+a[j]是負數,則開始於下標p的任意子序列都不會大於在下標i並且包含從a[i]到a[p-1]的子串行對應的子串行。因此,把i推進到j+1是安全的,不會錯過最優解。注意的是:雖然,如果有以a[j]

結尾的某序列和是負數就表明了這個序列中的任何乙個數不可能是與a[j]

後面的數形成的最大子串行的開頭,但是並不表明a[j]

前面的某個序列就不是最大序列,也就是說不能確定最大子串行在a[j]

前還是a[j]

後,即最大子串行位置不能求出。但是能確保maxsum

的值是當前最大的子串行和。

這個演算法還有乙個有點就是,它只對資料進行一次掃瞄,一旦a[j]被讀入處理就不需要再記憶。它是乙個聯機演算法

聯機演算法:在任意時刻演算法都能夠對它已讀入的資料給出當前資料的解。

常量空間線性時間的聯機演算法幾乎是完美的演算法。

其它

關於演算法三中提到的對數複雜度,除分治演算法外,還有對分查詢(已排序集合)、歐幾里得演算法(查詢最大公約數)、冪運算等,都有該特點。

時間複雜度比較(由小到大):o(1) < o(logn) < o(n) < o(nlogn) < o(n2) < o(2n) < o(n!) ,這有點數學常識的一眼就能比較出來。

最大欄位和

include include include include include using namespace std 最大欄位和問題描述 給定n個整數 可能為負數 組成的序列a 1 a 2 a 3 a n 求該序列如a i a i 1 a j 的子段和的最大值。當所給的整均為負數時定義子段和為0,...

最大欄位和

1049 最大子段和 難度 基礎題 n個整數組成的序列a 1 a 2 a 3 a n 求該序列如a i a i 1 a j 的連續子段和的最大值。當所給的整數均為負數時和為0。例如 2,11,4,13,5,2,和最大的子段為 11,4,13。和為20。input 第1行 整數序列的長度n 2 n 5...

最大欄位和

題目描述 給出一段序列,選出其中連續且非空的一段使得這段和最大。輸入格式 第一行 是乙個正整數n,表示了序列的長度。第二行 包含n個整數num i 描述了這段序列。輸出格式 第一行 乙個整數,為最大的子段和是多少。第二行 起始位置和終止位置 輸入樣例 72 4 3 1 2 4 3 輸出樣例 43 5...