486,動態規劃解最大子序和
技術標籤:資料結構和演算法動態規劃最大子序和LeetCode演算法
問題描述
給定一個整數陣列nums,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。
示例:
輸入: [-2,1,-3,4,-1,2,1,-5,4]
輸出: 6
解釋: 連續子陣列[4,-1,2,1]的和最大,為6。
動態規劃解決
這題是讓求最大的連續子序和,如果不是連續的非常簡單,只需要把所有的正數相加即可。但這裡說的是連續的,中間可能摻雜負數,如果求出一個最大子序和在加上負數肯定要比原來小了。解這題最簡單的一種方式就是使用動態規劃。
我們先來了解一下動態規劃的幾個步驟
1,確定狀態
3,確定初始條件以及邊界條件
4,計算結果。
最後一個不用看,只看前3個就行,因為前3個一旦確定,最後一個結果也就出來了。我們試著找一下
1,定義dp[i]表示陣列中前i+1(注意這裡的i是從0開始的)個元素構成的連續子陣列的最大和。
2,如果要計算前i+1個元素構成的連續子陣列的最大和,也就是計算dp[i],只需要判斷dp[i-1]是大於0還是小於0。如果dp[i-1]大於0,就繼續累加,dp[i]=dp[i-1]+num[i]。如果dp[i-1]小於0,我們直接把前面的捨棄,也就是說重新開始計算,否則會越加越小的,直接讓dp[i]=num[i]。所以轉移公式如下
dp[i]=num[i]+max(dp[i-1],0);
3,邊界條件判斷,當i等於0的時候,也就是前1個元素,他能構成的最大和也就是他自己,所以
dp[0]=num[0];
找到了上面的轉移公式,程式碼就簡單多了,來看下
public int maxSubArray(int[] num) {
int length = num.length;
int[] dp = new int[length];
//邊界條件
dp[0] = num[0];
int max = dp[0];
for (int i = 1; i < length; i++) {
//轉移公式
dp[i] = Math. max(dp[i - 1], 0) + num[i];
//記錄最大值
max = Math.max(max, dp[i]);
}
return max;
}
程式碼優化
仔細看下上面的程式碼會發現,我們申請了一個長度為length的陣列,但在轉移公式計算的時候,每次計算當前值的時候只會用到前面的那個值,再往前面就用不到了,這樣實際上是造成了空間的浪費。這裡不需要一個數組,只需要一個臨時變數即可,看下程式碼
public int maxSubArray(int[] num) {
int length = num.length;
int cur = num[0];
int max = cur;
for (int i = 1; i < length; i++) {
cur = Math.max(cur, 0) + num[i];
//記錄最大值
max = Math.max(max, cur);
}
return max;
}
總結
動態規劃最重要的3步就是先確定狀態,最關鍵的是找出轉移公式,最後再確定邊界條件,防止陣列越界等問題,這3步確定以後基本上就能解決了。