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