目录
01背包
300. 最长上升子序列
198. 打家劫舍
62. 不同路径
64. 最小路径和
72. 编辑距离
做动态规划题很重要的三个步骤:
第一步骤:定义数组元素的含义,确定状态首先提取【最后一步】,用一个数组,来保存历史数组,假设用一维数组 dp[] 吧。这个时候有一个非常非常重要的点,就是规定你这个数组元素的含义,例如你的 dp[i] 是代表什么意思?
第二步骤:找出数组元素之间的关系式,我觉得动态规划,还是有一点类似于我们高中学习时的归纳法的,当我们要计算 dp[n] 时,是可以利用 dp[n-1],dp[n-2].....dp[1],来推出 dp[n] 的,也就是可以利用历史数据来推出新的元素值,所以我们要找出数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],这个就是他们的关系式了。而这一步,也是最难的一步。
第三步骤:找出初始值。学过数学归纳法的都知道,虽然我们知道了数组元素之间的关系式,例如 dp[n] = dp[n-1] + dp[n-2],我们可以通过 dp[n-1] 和 dp[n-2] 来计算 dp[n],但是,我们得知道初始值啊,例如一直推下去的话,会由 dp[3] = dp[2] + dp[1]。而 dp[2] 和 dp[1] 是不能再分解的了,所以我们必须要能够直接获得 dp[2] 和 dp[1] 的值,而这,就是所谓的初始值。
由了初始值,并且有了数组元素之间的关系式,那么我们就可以得到 dp[n] 的值了,而 dp[n] 的含义是由你来定义的,你想求什么,就定义它是什么,这样,这道题也就解出来了。
参考连接:https://zhuanlan.zhihu.com/p/91582909
最基本的背包问题就是01背包问题(01 knapsack problem):一共有N件物品,第i(i从1开始)件物品的重量为w[i],价值为v[i]。在总重量不超过背包承载上限cap的情况下,能够装入背包的最大价值是多少?
第一步:dp[i][j]表示将前i件物品装进限重为j的背包可以获得的最大价值,不是前i件都装;
第二步:当 i > 0 时dp[i][j]
有两种情况:
dp[i−1][j]
;dp[i−1][j−w[i]] + v[i]
。即状态转移方程为
dp[i][j] = max(dp[i−1][j], dp[i−1][j−w[i]]+v[i]) // j >= w[i]
第三步:dp[N+1][cap+1] :dp[0][j]表示0个物品装入,价值为0;dp[i][0]背包容量为0,装不下任何东西,价值为0;
package cn.ren.demo;
public class Solution {
public static void main(String[] args) throws Exception {
int[] weight = new int[] {0,2,3,4,5,9};
int[] value = new int[] {0,3,4,5,8,10} ;
int cap = 20 ;
System.out.println(knapsack(weight, value, cap));
}
public static int knapsack(int[] W, int[] V, int cap) {
int m = V.length ;
int n = cap + 1 ; // 考虑第0个空间
int[][] dp = new int[m][n] ;
for ( int i = 0; i < m ; i ++ ) { // 选择0个物品
dp[i][0] = 0 ;
}
for (int j = 0; j < n; j ++ ) { // 容量为0
dp[0][j] = 0 ;
}
for (int i = 1; i < m; i ++ ){ // 从1开始可以省略上面初始化的步骤
for( int j = 1; j < n; j ++){ // 代表当前容量
if( W[i] > j ){
dp[i][j] = dp[i-1][j] ;
} else {
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-W[i]] + V[i]) ;
}
}
}
return dp[m-1][n-1] ;
}
}
class Solution {
public int lengthOfLIS(int[] nums) {
return DP(nums) ;
}
public int DP(int[] nums){
int max = 0 ;
int[] dp = new int[nums.length] ;
for( int i = 0; i < nums.length; i ++){
dp[i] = 1 ;
}
for(int i = 0; i < nums.length; i++){
for(int j = 0; j < i; j ++){
if(nums[j] < nums[i] && dp[i] < dp[j] + 1 ){
dp[i] = dp[j] + 1 ;
}
}
max = Math.max(max,dp[i]) ;
}
return max ;
}
}
class Solution {
public int rob(int[] nums) {
if(nums.length == 0){
return 0;
} else if(nums.length == 1){
return nums[0] ;
}
int[] dp = new int[nums.length] ;
dp[0] = nums[0] ;
dp[1] = Math.max(nums[0],nums[1]) ;
for( int i = 2; i < nums.length; i ++){
dp[i] = Math.max(dp[i-1],dp[i-2] + nums[i]) ;
}
return dp[nums.length-1] ;
}
}
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n] ;
for( int i = 0; i < m; i ++){
dp[i][0] = 1 ;
}
for( int j = 0; j < n; j ++){
dp[0][j] = 1 ;
}
for(int i = 1; i < m; i ++){
for(int j = 1; j < n; j ++){
dp[i][j] = dp[i-1][j] + dp[i][j-1] ;
}
}
return dp[m-1][n-1] ;
}
}
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length ;
int n = grid[0].length ;
int[][] dp = new int[m][n] ;
dp[0][0] = grid[0][0] ;
for( int i = 1; i < m; i ++){
dp[i][0] = dp[i-1][0] + grid[i][0] ;
}
for( int j = 1; j < n; j ++){
dp[0][j] = dp[0][j-1] + grid[0][j] ;
}
for( int i = 1; i < m ; i ++){
for( int j = 1; j < n; j ++){
dp[i][j] = Math.min(dp[i-1][j] + grid[i][j], dp[i][j-1]+grid[i][j]) ;
}
}
return dp[m-1][n-1] ;
}
}
https://leetcode-cn.com/problems/edit-distance/solution/xiong-mao-shua-ti-python3-dong-tai-gui-hua-yi-dong/
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length() ;
int n = word2.length() ;
int[][] dp = new int[m+1][n+1] ;
for(int i = 1; i <= m; i ++){
dp[i][0] = dp[i-1][0] + 1 ;
}
for(int j = 1; j <= n; j ++){
dp[0][j] = dp[0][j-1] + 1 ;
}
for(int i = 1; i <= m; i ++){
for( int j = 1; j <= n; j ++){
if(word1.charAt(i-1) == word2.charAt(j-1)){
dp[i][j] = dp[i-1][j-1] ;
} else {
dp[i][j] = Math.min(Math.min(dp[i-1][j-1],dp[i-1][j]),dp[i][j-1]) + 1 ;
}
}
}
return dp[m][n] ;
}
}