1. 程式人生 > 實用技巧 >動態規劃

動態規劃

動態規劃

動態規劃背後的基本思想非常簡單。大致上,若要解一個給定問題,我們需要解其不同部分(即子問題),再根據子問題的解以得出原問題的解

動態規劃框架

//動態規劃框架
//初始化 base case
dp[0][0][...] = base
//進行狀態轉移
for '狀態1' in '狀態1的所有取值':
    for '狀態2' in '狀態2的所有取值':
        for ...
            dp[狀態1][狀態2][...] = 求最值(選擇1,選擇2...)

通俗的解釋:通過子問題的解逐步累積推匯出原問題的解。

例項1:求最長迴文子串

//dp[j][i] 字串從j->i是否為迴文數
//動態迴歸方程d[i-1][j+i]是否為迴文數
public String longestPalindrome(String s) {
    int len=s.length();
    boolean[][] dp = new boolean[len][len];
    int max=-1;
    String str="";
    for (int i = 0; i < len; i++) {
        for (int j = 0; j <= i; j++) {
            if (s.charAt(j) == s.charAt(i) && (i - j <= 2 || dp[j+1][i-1]))
                dp[j][i] = true;
            if(dp[j][i] && i-j>max) {
                max=i-j;
                str=s.substring(j,i+1);
            }

        }
    }
    return str;
}

例項2:輸入一個整型陣列,數組裡有正數也有負數。陣列中的一個或連續多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)

/*
字串問題一般都是分解子問題的過程,假設陣列長度只有1個,不用求就只能是這個一元素的大小了,如果是2個元素,3個元素呢

元素個數 最大和

1 		[0]
2 		max([0]+[1],[1])
3 		max([1]+[2],[2])
4 		max([2]+[3],[3])
...
...
n max([n-1]+[n],[n])

分析:
1.當[n]>=[n-1]+[n]的時候說明[n-1]對結果產生了副作用,以n-1結尾的錢n項和還不如n項大,那麼n項就作為起點位置了
2.當[n]<[n-1]+[n]的時候說明[n-1]對結果產生了正面作用,繼續判斷下一部分
3.綜合以上分析這明顯就是動態規劃的特徵(核心思想是把原問題分解成子問題進行求解,也就是分治的思想)
4.綜合起來dp[i] 作為以i結尾連續字串最大和,本質就只有三行程式碼
	max = dp[0] = nums[0];
	dp[i] = Math.max(dp[i - 1] + nums[i], nums[i])
	max = Math.max(max, dp[i]);
5. 當[n]>[n-1]+[n]時記錄起始位置下標,當[n-1]+[n]>[n]時記錄結束座標,dp[i]>max時,則記錄最大和
*/
 //java程式碼
 public int maxSubArray(int[] nums) {
        int len = nums.length;
        int[] dp = new int[len];
        dp[0] = nums[0];
        int max = dp[0];
        for (int i = 1; i < len; i++) {
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            max = Math.max(max, dp[i]);
        }
        return max;
    }