1. 程式人生 > 其它 >486,動態規劃解最大子序和

486,動態規劃解最大子序和

技術標籤:資料結構和演算法動態規劃最大子序和LeetCode演算法

在這裡插入圖片描述

問題描述

給定一個整數陣列nums,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。

示例:

輸入: [-2,1,-3,4,-1,2,1,-5,4]

輸出: 6

解釋: 連續子陣列[4,-1,2,1]的和最大,為6。


動態規劃解決

這題是讓求最大的連續子序和,如果不是連續的非常簡單,只需要把所有的正數相加即可。但這裡說的是連續的,中間可能摻雜負數,如果求出一個最大子序和在加上負數肯定要比原來小了。解這題最簡單的一種方式就是使用動態規劃。


我們先來了解一下動態規劃的幾個步驟

1,確定狀態

2,找到轉移公式
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步確定以後基本上就能解決了。