給定k個整數組成的序列
,連續子列被定義為
其中 1≤
i≤j≤
k 。「最大子列和」則被定義為所有連續子列元素的和中最大者。例如給定序列
,其連續子列
有最大的和
20 。現要求你編寫程式,計算給定整數序列的最大子列和。
本題旨在測試各種不同的演算法在各種資料情況下的表現。各組測試資料特點如下:
輸入格式:
輸入第1行給出正整數k (≤100000);第2行給出k個整數,其間以空格分隔。
輸出格式:
在一行中輸出最大子列和。如果序列中所有整數皆為負數,則輸出0。
輸入樣例:
6 -2 11 -4 13 -5 -2
輸出樣例:
20問題分析:
首先最樸素的方法是暴力求解o(
n3)
直接兩個for迴圈枚舉子序列的首尾,然後再來個迴圈計算序列的和,每次更新和的最大值。但是這種方法的複雜度是o(
n3) ,效率太低了。
第二種方法是預處理o(
n2)
在讀入的時候將前面數的和放在陣列中,就能得到乙個陣列su
m[i]
儲存前i個數的和。然後兩重迴圈列舉首尾,利用su
m 陣列迅速求出子串行的和。其實這種方法只是優化了前面那種方法的計算和的迴圈,複雜的是o(
n2) 。
第三種是利用分治思想o(
nlog
n)分治演算法看**不是很好理解,其實思想很簡單,就是把序列分成兩塊計算,用遞迴分別求出兩塊序列中的最大子串行和,然後從序列中間向兩邊遍歷求出包含中心的序列的最大和。返回最大的那個序列和。
用分治演算法的複雜度好了一些,是o(
nlog
n),雖然不是最優解,但是理解這種演算法的確能讓我們對遞迴理解得更加深刻。
第四種是累積遍歷演算法o(
n)遍歷序列的時候對sum進行累計,如果sum累積後小於0的話就把sum重置為負無窮,每次更新sum的最大值。最後便能求出最大值。
其實這個演算法就是把序列分為好幾塊,每一塊滿足:對於任意k,前k個數的和不會小於0(小於0就會**成兩塊了),當前i個數的和大於最大值時就進行更新,而最大值的左邊界就是該塊序列的第乙個,右邊界是第i個。時間複雜度為o(n),而且可以一邊讀取一邊處理,不需要開闢陣列來存,空間也很省。
第五種是動態規劃o(
n)dp做法是很普遍的做法,只要想出狀態轉移方程就可以很快做出來了。
狀態轉移方程:su
m[i]
=max
. (su
m[i]
記錄以a[
i]為子串行末端的最大連續和。)在dp的過程中便可以更新su
m 陣列的最大值以及兩個邊界。
其實完全可以不用陣列,累計su
m 直到su
m+a<
a ,把su
m 賦值為
a ,更新最大值就行了。你會發現這跟第4種方法是一樣的。。。只是判斷條件不一樣,乙個是su
m<=
0乙個是su
m+a<
a 。(其實是一樣的)所以複雜度和第四種是一樣的都是o(n)。
暴力求解
int maxsubseqsum1( int a, int n )
/* j迴圈結束 */
} /* i迴圈結束 */
return maxsum;
}
預處理
int maxsubseqsum2( int a, int n )
/* j迴圈結束 */
} /* i迴圈結束 */
return maxsum;
}
分治思想
int max3( int a, int b, int c )
int divideandconquer( int list, int left, int right )
/* 下面是"分"的過程 */
center = ( left + right ) / 2; /* 找到中分點 */
/* 遞迴求得兩邊子列的最大和 */
maxleftsum = divideandconquer( list, left, center );
maxrightsum = divideandconquer( list, 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 max3( maxleftsum, maxrightsum, maxleftbordersum + maxrightbordersum );
}int maxsubseqsum3( int list, int n )
累積遍歷演算法
int maxsubseqsum4( int a, int n )
return maxsum;
}
動態規劃演算法
sum←(-∞)
max←(-∞)
for i←1 to len do
if sum+arr[i]else
sum←sum+arr[i]
end if
if maxif
end for
return max
最大子串行和問題
問題 給定一整數序列a1,a2,an 可能有負數 求a1 an的乙個子串行ai aj,使得ai到aj的和最大 例如 整數序列 2,11,4,13,5,2,5,3,12,9的最大子串行的和為21。對於這個問題,最簡單也是最容易想到的那就是窮舉所有子串行的方法。利用三重迴圈,依次求出所有子串行的和然後取...
最大子串行和問題
問題描述 給定乙個整數序列 可能有負數 求一子串行 記為l 使得該子串行所有元素之和最大。例 給定序列 2,11,4,13,5,2,則最大子串行和為20 11,4,13 方法一 遍歷窮舉 o n 2 略方法二 分治遞迴 o n logn 思路 將輸入序列l分為左右兩個子串行l1和l2,則l 只可能以...
最大子串行和問題
問題描述 求 2,11,4,13,5,2 的最大子串行和。方法一 使用3層for迴圈巢狀,窮舉式的嘗試所有的可能,如下 public class demo1 return maxsum public static void main string args system.out.println 最大...