当前位置:   article > 正文

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

动态规划习题

目录

带权值的最小路径和

背包问题(二)

分割回文串-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. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/404449
推荐阅读
相关标签
  

闽ICP备14008679号