动态规划题目练习

目录

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背包问题(01 knapsack problem):一共有N件物品,第i(i从1开始)件物品的重量为w[i],价值为v[i]。在总重量不超过背包承载上限cap的情况下,能够装入背包的最大价值是多少?

第一步:dp[i][j]表示将前i件物品装进限重为j的背包可以获得的最大价值,不是前i件都装;

第二步:当 i > 0 时dp[i][j]有两种情况:

  1. 装不下,不装入第i件物品,即dp[i−1][j]
  2. 能装下,装入第i件物品,即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] ;
	}

}


 

300. 最长上升子序列

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 ;
    }
}

198. 打家劫舍

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] ;
    }
}

62. 不同路径

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] ;
	}
}

64. 最小路径和

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] ;
    }
}

72. 编辑距离

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] ;
    }
}

 

 

 

你可能感兴趣的:(#,算法分类整理)