• 算法学习 | 动态规划经典练习题合集


    目录

    带权值的最小路径和

    背包问题(二)

    分割回文串-ii

    编辑距离 


    带权值的最小路径和

    OJ链接:CC86-带权值的最小路径和

    题目描述 

    给定一个由非负整数填充的m x n的二维数组,现在要从二维数组的左上角走到右下角,请找出路径上的所有数字之和最小的路径。
    注意:你每次只能向下或向右移动。

    例如

    输入:[[1,2],[5,6],[1,1]]

    输出:8

    根据题目要求,每次只能向下或向右移动

    对题目进行dp状态分析 

    状态定义:F(i,j):从(0,0)到(i,j)的最短路径和

    状态方程:F(i,j) = min( F(i-1,j),F(i,j-1) ) + grid[i][j]

    初始值:F(0,0) = grid[0][0]

    返回值:F(m - 1,n - 1)

     

    1. import java.util.*;
    2. public class Solution {
    3. 状态定义:F(i,j):从(00)到(i,j)的最短路径和
    4. 状态方程:F(i,j) = min(F(i - 1,j),F(i,j - 1)) + grid[i][j]
    5. 初始值:F(0,i) = 1,F(i,0) = 1;
    6. 返回值:F(m-1,n-1)
    7. */
    8. public int minPathSum (int[][] grid) {
    9. // write code here
    10. int m = grid.length;
    11. int n = grid[0].length;
    12. int[][] dp = new int[m][n];
    13. dp[0][0] = grid[0][0];
    14. for (int i = 1; i < m; i++) {
    15. dp[i][0] = dp[i-1][0] + grid[i][0];
    16. }
    17. for (int i = 1; i < n; i++) {
    18. dp[0][i] = dp[0][i-1] + grid[0][i];
    19. }
    20. for (int i = 1; i < m; i++) {
    21. for (int j = 1; j < n; j++) {
    22. dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1]) + grid[i][j];
    23. }
    24. }
    25. return dp[m-1][n-1];
    26. }
    27. }

    背包问题(二)

    OJ链接:背包问题(二) 

    题目描述 

    有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值.

    问最多能装入背包的总价值是多大?

    例如

    输入:m = 10   A = [2, 3, 5, 7]   V = [1, 5, 2, 4] 

    返回:9

    dp状态分析

    状态定义:F(i,j):表示前i个物品放在大小为j的背包中所获得的最大价值

    状态递推:有两种情况:一种是可以放下,一种是放不下

       ①如果可以放下:F(i,j) = max{ F(i - 1,j),F(i - 1,j - a[i]) + v[i] }

       ②如果放不下:F(i,j) = F(i - 1,j),因为背包的大小不足以放下第i个物品,因此这个状态的值应该为上一个状态的值

    初始值:第0行和第0列的值都为0,表示未装物品

    返回值:F(n,m)

    1. public class Solution {
    2. 状态定义:F(i,j):前i个物品放在大小为j的背包中所获得的最大价值
    3. 状态递推:如果放不下:F(i,j) = F(i-1,j)
    4. 如果能放下:F(i,j) = max{F(i-1, j), F(i-1, j-a[i]) + v[i]}
    5. 初始值:F(0, j) = F(i, 0) = 0
    6. 返回值:F(n, m),m为背包大小,n为物品数量
    7. */
    8. public int backPackII(int m, int[] a, int[] v) {
    9. // write your code here
    10. int n = a.length;
    11. int[][] dp = new int[n + 1][m + 1];
    12. //初始化
    13. for (int i = 0; i <= m; i++) {
    14. dp[0][i] = 0;
    15. }
    16. for (int i = 1; i <= n; i++) {
    17. dp[i][0] = 0;
    18. }
    19. for (int i = 1; i <= n; i++) {
    20. for (int j = 1; j <= m; j++) {
    21. if (j < a[i - 1]) {
    22. dp[i][j] = dp[i - 1][j];
    23. } else {
    24. int newValue = dp[i - 1][j - a[i - 1]] + v[i - 1];
    25. dp[i][j] = Math.max(newValue, dp[i - 1][j]);
    26. }
    27. }
    28. }
    29. return dp[n][m];
    30. }
    31. }

    分割回文串-ii

    OJ链接:CC19-分割回文串-ii

    题目描述

    给出一个字符串s,分割s使得分割出的每一个子串都是回文串

    计算将字符串s分割成回文分割结果的最小切割数

    例如:给定字符串s="aab",

    返回1,因为回文分割结果["aa","b"]是切割一次生成的。

    dp状态分析

    状态定义:F(i):到第i个字符最小的拆分次数

    状态递推:F(i) = min(F(i), F(j) + 1)
    初始化:F(i) = i - 1(表示到第i个字符所需要的最大拆分次数)

    返回值:F(n)

    1. import java.util.*;
    2. public class Solution {
    3. /**
    4. 状态定义:F(i):到第i个字符最小的拆分次数
    5. 状态递推:F(i) = min(F(i), F(j) + 1)
    6. 初始值:F(i) = i - 1(表示到第i个字符所需要的最大拆分次数)
    7. 返回值:F(n)
    8. */
    9. public int minCut (String s) {
    10. // write code here
    11. int n = s.length();
    12. if (n == 0) {
    13. return 0;
    14. }
    15. int[] dp = new int[n + 1];
    16. for (int i = 0; i <= n; i++) {
    17. dp[i] = i - 1;
    18. }
    19. for (int i = 1; i <= n; i++) {
    20. for (int j = 0; j < i; j++) {
    21. if (isPal(s, j, i - 1)) {
    22. dp[i] = Math.min(dp[i], dp[j] + 1);
    23. }
    24. }
    25. }
    26. return dp[n];
    27. }
    28. private boolean isPal(String s, int start, int end) {
    29. while (start < end) {
    30. if (s.charAt(start) != s.charAt(end)) {
    31. return false;
    32. }
    33. start++;
    34. end--;
    35. }
    36. return true;
    37. }
    38. }

    编辑距离 

    OJ链接:CC77-编辑距离

    题目描述

    给定两个单词word1和word2,请计算将word1转换为word2至少需要多少步操作。
    你可以对一个单词执行以下3种操作:
    a)在单词中插入一个字符
    b)删除单词中的一个字符
    c)替换单词中的一个字符 

    例如

    输入:“ab”,“bc”

    输出:2 

    dp状态分析

    状态定义:F(i,j):word1前i个字符转换为word2的前j个字符需要的最少步数

    状态方程:F(i,j) = min{ F(i-1,j)+1,F(i,j-1)+1,F(i-1,j-1)+(word1[i] == word2[j] ? 0 : 1) }

    初始化:F(i,j) = min{F(i-1, j)+1, F(i, j-1)+1, F(i-1, j-1)+(word1[i] == word2[j] ? 0 : 1)}

    初始值一定要是空字符串

    F(i,0) = i:word与空串的编辑距离,删除操作

    F(0,i) = i:空串与word的编辑距离,增加操作

    返回值:F(m,n)

     

    1. import java.util.*;
    2. public class Solution {
    3. /**
    4. 状态定义:F(i,j):word1的前i个字符变成word2的前j个字符的最小步数
    5. 状态方程:F(i,j) = min{F(i-1, j)+1, F(i, j-1)+1, F(i-1, j-1)+(word1[i] == word2[j] ? 0 : 1)}
    6. 初始化:
    7. F(i,0) = i:word与空串的编辑距离,删除操作
    8. F(0,i) = i:空串与word的编辑距离,增加操作
    9. 返回值:F(m,n)
    10. */
    11. public int minDistance (String word1, String word2) {
    12. // write code here
    13. //word与空串之间的编辑距离为word长度
    14. if (word1.isEmpty() || word2.isEmpty()) {
    15. return Math.max(word1.length(), word2.length());
    16. }
    17. int m = word1.length();
    18. int n = word2.length();
    19. int[][] dp = new int[m+1][n+1];
    20. for (int i = 0; i <= m; i++) {
    21. dp[i][0] = i;
    22. }
    23. for (int i = 0; i <= n; i++) {
    24. dp[0][i] = i;
    25. }
    26. for (int i = 1; i <= m; i++) {
    27. for (int j = 1; j <= n; j++) {
    28. dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]);
    29. //判断word1的第i个字符与word2的第j个字符是否相等
    30. if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
    31. //字符相等,F(i-1, j-1)编辑距离不变
    32. dp[i][j] = Math.min(dp[i][j], dp[i - 1][j - 1]);
    33. } else {
    34. //字符不相等,F(i-1, j-1)编辑距离+1
    35. dp[i][j] = Math.min(dp[i][j], dp[i - 1][j - 1] + 1);
    36. }
    37. }
    38. }
    39. return dp[m][n];
    40. }
    41. }

  • 相关阅读:
    Qt 输入组控件(Input Widgets)& 显示组控件(Display Widgets)详解
    在windows上配置git支持多账号
    国内工业控制系统
    华为机考:HJ2 计算某字符出现次数
    A、B机器正常TCP连接后,B突然断网,A处于什么状态?
    Java 抽象类能不能实例化
    pdf转word文档方法
    VSCode 环境配置原理
    七牛云图片上传
    PHP递归实现无限级分类
  • 原文地址:https://blog.csdn.net/qq_58284486/article/details/127569179