初探動態規劃

Q:爲何要學動態規劃?
A:由於筆試必考。算法

Q:爲何筆試喜歡考動態規劃?
A:由於動態規劃比較好出題,能夠檢驗思考方式,並且相對比較難。bash

Q:爲何動態規劃難?
A:就像高考最後的物理大題同樣,解題思路大同小異,但每一個人作出來都不同,更況且不少人都還作不出來。學習

Q:什麼是動態規劃?
A:這個本身 Google 吧,不在論述範圍以內。測試

Q:看懂這篇文章須要什麼水準? A:懂遞歸,會寫遞歸。優化

先來一個簡單例子:斐波那契數列(F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)n>=2,n∈N*),這個例子都被用爛了。ui

// 遞歸版本,通俗易懂  版本一
public int fibonacci(int n) {
    return solve(n);
}
public int solve(int n) {
    if (n < 1) {
        return 0;
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    return solve(n - 1) + solve(n - 2);
}
複製代碼
// 記憶搜索或者備忘錄版本 版本二
public int[] dp;
public int fibonacci(int n) {
    dp = new int[n + 1];
    for (int i = 0; i < n + 1; i++) {
        dp[i] = -1;
    }
    return solve(n);
}
public int solve(int n) {
    if (n < 1) {
        return 0;
    }
    if (n == 1 || n == 2) {
        return 1;
    }
    if (dp[n] != -1) {
        return dp[n];
    }
    return solve(n - 1) + solve(n - 2);
}
複製代碼
//動態規劃版本 版本三
public int[] dp;
public static int fibonacci(int n) {
    dp = new int[n + 1];
    for (int i = 0; i < n + 1; i++) {
        dp[i] = -1;
    }
    dp[1] = 1;
    dp[2] = 1;
    for (int i = 3; i < n + 1; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}
複製代碼

上述三個算法耗費的實際時間(注意是實際時間,不是算法的時間複雜度)愈來愈少,耗費的實際空間(注意是實際空間,不是算法空間複雜度)。spa

代碼就先放在這裏,咱們聊聊別的。後面兩種算法的意義何在?優化。如今主流想法通常是用空間換時間,由於內存愈來愈大。code

什麼樣子的題能夠用動態規劃解決?能用遞歸解決的問題,才能用動態規劃,不能用遞歸解決的問題,確定不能用動態規劃。遞歸

問題就變簡單了,動態不會寫,難道連遞歸都不會寫嗎?那咱們就從遞歸開始寫吧,來一道題:打家劫舍。內存

198 打家劫舍
你是一個專業的小偷,計劃偷竊沿街的房屋。 每間房內都藏有必定的現金,影響你偷竊的惟一制約因素就是相鄰的房屋裝有相互連通的防盜系統,若是兩間相鄰的房屋在同一夜被小偷闖入,系統會自動報警。 具體測試用例能夠去 LeetCode 搜索。

分析題幹,小偷每進一個房屋,有兩種選擇:搶或者不搶。搶的後果就是相鄰的一家就不能進去,不搶沒有任何後果相鄰的一家也能夠繼續選擇進去,最終獲得的搶劫的金錢數目。

public int rob(int[] nums) {
    return solve(nums.length - 1, nums);
}
public int solve(int index, int[] nums) {
    if (index < 0) {
        return 0;
    }
    int currentMoney = nums[index] + solve(index - 2, nums); //這家搶了,就不能搶下一家
    int nextMoney = solve(index - 1, nums); //不搶這家,繼續去下一家看看
    return Math.max(currentMoney, nextMoney); //返回搶錢多選擇
}
複製代碼

這個算法在 LeetCode 確定過不了,甚至緣由都不用想,確定由於遞歸太深超時了。既然超時,就要考慮優化,常規想法應該是用空間換時間。仿照上面「斐波那契數列」的例子,進行優化,寫出版本二和版本三吧,版本三就是動態規劃了。

end


Q:爲何不講理論?
A:想學理論去看「算法導論」吧,這本書很是值得學習。

Q:爲何是在講遞歸?
A:由於遞歸是動態規劃的基礎,遞歸優化到最後就是動態規劃。

Q:爲何採起這種方式? A:動態規劃是一種思路問題,不一樣的題特性不同。從遞歸開始進而優化的方式很是易學,並且比較容易速成。

過幾天再寫一篇關於遞歸優化的問題,這種方式真的好速成。剛開始應該會多浪費一點時間的,練習十幾道題事後就不用每次寫三份代碼了。

從如今開始,忘掉動態規劃,從遞歸開始。

相關文章
相關標籤/搜索