1. 程式人生 > 其它 >動態規劃小白總結

動態規劃小白總結

技術標籤:leetcode動態規劃演算法java

**動態規劃 --小白學習之路
(強調:我就是個新手,我就是個弟弟,程式碼寫的比較爛大佬們別罵我)
題目分類:
1.最值問題(理解為比較題)
2.數量問題(理解為加法題)
3.存在性問題(理解為判斷題)
4.以上都是小弟自己瞎總結,大佬們別罵
解題思路:
將大問題分為一個個等價的子問題
題目(最值問題):
力扣劍指offer 42 .連續子陣列的最大和
輸入一個整型陣列,陣列中的一個或連續多個整陣列成一個子陣列。求所有子陣列的和的最大值。
思路:最值問題可以理解為比較型別的問題,當我們需要找到當前陣列的最大和,那麼只有兩種方法可以到達當前陣列元素,

1.當前元素的前一個元素加上當前元素總和變得更大,則取當前陣列和前一個數組的和。
2.反之,取當前元素為唯一元素 。
分割子問題為: fn[i] = Math.max(fn[i - 1] + nums[i], nums[i]);
那麼只需要遍歷一次即可得到最大的和

class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];
        int [] fn = new int[nums.length];
        fn[0] = nums[0];
        for(int i = 1; i < nums.length; i++) {
            fn[i] = 0;
            fn[i] = Math.max(fn[i - 1] + nums[i], nums[i]);
            max = Math.max(fn[i] , max);
        }
        return max;
    }
}

力扣322零錢兌換

給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
你可以認為每種硬幣的數量是無限的。
思路:和上一題一樣,目前只有coins裡面的錢幣的金額才能到達amount,那麼到達amount的方式只有

for(int i = 0; i < coins.length; i++) {
	amount - coins[i] //這些
}
//換示例來說: 假如coins中有1,2,5面值的錢幣,那麼到達最終amount的前一步只能是amount - 1 , amount - 2 ,amount - 5這三種方式

那麼分割為子問題式子為:

  for(j = 0; j < n; j++) {
           if(i >= coins[j] && f[i - coins[j]] != Integer.MAX_VALUE)
           f[i] = Math.min(f[i - coins[j]] + 1, f[i]);
   }

完整程式碼為:

class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] f = new int [amount + 1] ;
        int n = coins.length;
        f[0] = 0;
        int i , j;
        for(i = 1; i <= amount; i++) {
            f[i] = Integer.MAX_VALUE;
            for(j = 0; j < n; j++) {
                if(i >= coins[j] && f[i - coins[j]] != Integer.MAX_VALUE)
                f[i] = Math.min(f[i - coins[j]] + 1, f[i]);
            }
        }
        if(f[amount] == Integer.MAX_VALUE) return -1;
        else return f[amount];
    }
}

題目(數量問題)
力扣62不同路徑
一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記為 “Start” )。

機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為 “Finish” )。

問總共有多少條不同的路徑?
在這裡插入圖片描述
思路:我們到達最右下角,只有他的上面和他的左邊才能到達,那麼分割子問題為:想要知道到達當前的點的上面到達的方法和左邊到達的方法即可
完整的程式碼為

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] f = new int[m][n];
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(i == 0 || j == 0) f[i][j] = 1;
                else {
                    f[i][j] = f[i - 1][j] + f[i][j - 1];  //加減法問題
                }
            }
        }
        return f[m - 1][n - 1];
    }
}

力扣 70 爬樓梯
假設你正在爬樓梯。需要 n 階你才能到達樓頂。

每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?

注意:給定 n 是一個正整數。

思路:假如向跳到當前的樓梯,那麼你只有兩種方法,你可以從比當前 臺階少一個的臺階跳上來,也可以從當前臺階少兩個臺階的地方跳上來,是不是似曾相識的感覺哈哈哈哈
完整程式碼:

class Solution {
    public int climbStairs(int n) {
        int []fn = new int[n + 1];
        fn[0] = 1;
        fn[1] = 1;
        for(int i = 2; i <= n; i++) {
            fn[i] = fn[i - 1] + fn[i - 2];
        }
        return fn[n];
    }
}

題目(存在性問題)
力扣55 跳躍遊戲
給定一個非負整數陣列 nums ,你最初位於陣列的 第一個下標 。

陣列中的每個元素代表你在該位置可以跳躍的最大長度。

判斷你是否能夠到達最後一個下標。

思路:這題其實用動態規劃太慢了,自己體會把嘿嘿

class Solution {
    public boolean canJump(int[] nums) {
        boolean [] f = new boolean[nums.length];
        f[0] = true;
        for(int i = 1; i < nums.length; i++) {
            f[i] = false;
            for(int j = 0; j < i; j++) {
                if(f[j] == true && i - j<= nums[j]) {
                    f[i] = true;
                    break;
                }
            }
        }
        return f[nums.length - 1];
    }
}