最大連續子串行和 遞迴和動態規劃

2022-09-02 12:12:10 字數 3974 閱讀 3136

問題描述:

給定乙個整數序列,a0, a1, a2, …… , an(項可以為負數),求其中最大的子串行和。如果所有整數都是負數,那麼最大子串行和為0;

方法一:

用了三層迴圈,因為要找到這個子串行,肯定是需要起點和終點的,所以第一層迴圈確定起點,第二層迴圈確定終點,第三層迴圈在起點和終點之間遍歷。時間複雜度:o(n^3)

package secondcha;

public class maxsum1

} return maxsum;

}

public static void main(string args) ;

system.out.println(maxsubsequence(a));

}}

方法二:

只用了兩層迴圈,相當於是第一層用來找到每個可能的子串行的起點,而第二個迴圈直接從第一層確定的起點往陣列結尾遍歷,在遍歷的過程中同時也計算序列值。前兩種方法都是窮舉法,都是把所有可能的子串行都找出來,然後計算值再和最大值比較。

package secondcha;

public class maxsum2

} return maxsum;

} public static void main(string args) ;

system.out.println(maxsubsequence(a));

}}

方法三:

對於一數字序列,其最大連續子串行和對應的子串行可能出現在三個地方。或是整個出現在輸入資料的前半部(左),或是整個出現在輸入資料的後半部(右),或是跨越輸入資料的中部從而佔據左右兩半部分。前兩種情況可以通過遞迴求解,第三種情況可以通過求出前半部分的最大和(包含前半部分的最後乙個元素)以及後半部分的最大和(包含後半部分的第乙個元素)而得到,然後將這兩個和加在一起即可。

主要從遞迴的角度分析,把問題分為了小問題,處理的過程都一樣,嗯,所以就用遞迴了。然後遞迴重要在於理解兩步,過程和終點。

首先分析終點,子問題一步步被劃分,最終,明顯看出,原始序列最終會被分為乙個長度為1的子串行(乙個大於1的數一直除,肯定會到1的),把長度為1的子串行當成原問題,那麼根據題意,如果是正數,就要,如果是負數,不如不要,就為0。所以,遞迴的終點設定得正確。

然後分析過程,分析遞迴的過程,在debug的過程中,你能發現,遞迴最開始是一直拆分子問題,直到到達遞迴終點再一層一層倒著返**用結果。可以把遞迴過程看成乙個二叉樹,所以遞迴終點就是此遞迴過程二叉樹的最後一層,而在以下程式中, maxleftsum = maxsubsum(a,left,center); 這句就是左孩子,maxrightsum =

maxsubsum(a,center+1,right);就是右孩子。而左孩子語句先執行,所以過程最開始一定是往左下方向直到第乙個終點,觀察程式中的陣列,第乙個終點之前前肯定是傳遞了乙個的陣列進去,再一分為二,然後傳遞進去返回4,傳遞-3進去,返回0,再把他們左右序列最大值(因為兩序列各只有乙個,且這裡必須包含左序列最右和右序列最左,所以這裡就是這倆序列自身)加起來,為1。分析了這個問題的規模最小的問題,發現了這個遞迴的過程確實沒有毛病。

理解了終點和過程,那麼這個遞迴你也就理解了。

但是首先你得先想到這種思想,你才有前提寫出這遞迴**。

package secondcha;

public class maxsum3

center = (left + right)/2;

maxleftsum = maxsubsum(a,left,center);

maxrightsum = maxsubsum(a,center+1,right);

maxleftbordersum = 0;

leftbordersum = 0;

for(i = center;i >= left;i--)

maxrightbordersum = 0;

rightbordersum = 0;

for(i = center+1;i <= right;i++)

return max(maxleftsum,maxrightsum,maxleftbordersum + maxrightbordersum);

}

static int max(int a, int b, int c)

public static void main(string args) ;

int left=0;

int right=a.length-1;

system.out.println(maxsubsum(a,left,right));

}}

方法四:

這種方法應該也算動態規劃吧,畢竟把遞迴變成了非遞迴(但我這麼理解不對,非遞迴不等於動態規劃)。演算法書說這是聯機演算法,特點是僅需要常量空間和線性時間執行。

重點還是在於理解算

1.只有乙個for迴圈,迴圈裡的j變數理解成序列的起點,但是這個起點有時會跳過若干數,當當前計算的序列a[i]到a[j]的和thissum一旦為負時,則thissum歸零,因為for迴圈的迴圈變數加1,則從a[j+1]開始加和,即起點跳到了負數和的子串行的下乙個數字。

2.理解這樣的事實,乙個子串行必然是以正數開頭的,因為如果以負數開頭,那麼去掉這個子串行,那得到乙個更優解。

3.還有這麼個事實,乙個子串行,如果一旦他的前若干個數字組成的新的個數更少的子串行的和為負數,那麼去掉這個子串行,便能得到了乙個更優解。

4.maxsum若遇到更大的和則更新,若遇到更小的和,則不更新(沒有動作)。thissum則充分利用了第二個事實,當某個時刻子串行為負數,則歸零即相當於去掉了這子串行所有數字,從下乙個數字從新開始加和。

5.其實第二個事實,不是那麼好理解,關鍵在於,去掉是當一旦出現了和為負數(之前的和都是》=0的,但是加了下乙個數後和就為負數了)的子串行,就去掉這個子串行,而且這時,子串行最後乙個數肯定為負數,因為是沒加最後乙個數時和還為正數,但一加上了就變成負數,所以這最後乙個數肯定是負數。假設這個負數為a[i],現在歸零了,從a[i+1]開始加和了,思考以a[i]為結果的剛才去掉的這個序列(這裡指去掉的子串行的任意數到這個序列的最後乙個數,的這些所有可能的子串行,因為是要求連續,所以是任意到結尾的某個序列考慮是否該加回去)是不是不該去掉呢,為了證明,我們可以從去掉的序列的最後乙個a[i](第一種可能是只有最後那個數)開始加回去,你會加上a[i],因為a[i]是負數,所以加了和反而變小了,不該加。如果加上a[i-1]和a[i]呢,a[i-1]和a[i]的和肯定也是負數,這個負數可能比a[i]小,也可能大但肯定是個負數(舉例:1,2,-5和2,-1,-5),前者是大一點的負數,後者是小一點的負數,但是必然的,加回去的序列和肯定還是負數,共同點是-5是造成序列和變成負數的那個第乙個數,同理可得從任意處開始到結尾的序列的和必須也是負數,即是所有這些可能的序列都不應該加回去。——所以,一旦序列和為負數,那麼這個序列就應該去掉了。(不會出現這種情況,比如去掉這個子串行2,1,-5,1(和為-1),因為當i移動到-5時,就已經去掉了,也證明了去掉的子串行的最後乙個數是負數)

package secondcha;

public class maxsum4

return maxsum;

}

public static void main(string args) ;

system.out.println(maxsubsequence(a));

}}

動態規劃 最大連續子串行和

題目大意就是讓你選出一段和最大的連續序列,當有幾個序列和並列時,選出下標最小的的連續序列。可以採用動態規劃的思想解決,設一連續序列為a 0 a 1 a n 分別以a 0 a 1 a n 結尾的最大序列和為d 0 d 1 d n 若d i 1 0,則d i d i 1 a i 若d i 1 0,則d ...

動態規劃 最大連續子串行和

動態規劃 最大連續子串行和 問題描述 給定乙個數字序列a1,a2,an,求i,j 1 i j n 使得ai aj最大,輸出這個最大和。樣例 211 413 5 2顯然 11 4 13 20 為和最大的選取情況,因此最大和為20 下面介紹動態規劃的做法,複雜度為o n 讀者會發現其實左端點的列舉是沒有...

動態規劃 最大連續子串行和

給定乙個數字序列,a1,a2,an,求i,j 1 i j n 使得ai aj最大,輸出這個最大和。樣例輸入 2 11 4 13 5 2 輸出 20 即11 4 13 20 最大 分析 如果暴力做的話,乙個列舉,需要o n 2 在計算需要o n 一共需要o n 3 因為重複計算的太多了,還是設定乙個d...