1. 题目
- 给定不同的面额的硬币coins和一个总金额amount。编写一个函数来计算可以凑成总金额所需最少的硬币个数。https://leetcode-cn.com/problems/coin-change/
- 给定两个单词word1和word2,计算出将word1转换成word2所使用的最少操作数。https://leetcode-cn.com/problems/edit-distance/
2. 基本知识
这两天使用的还是动态规划的知识。
3. 算法题解
3.1 给定不同的面额的硬币coins和一个总金额amount。编写一个函数来计算可以凑成总金额所需最少的硬币个数
如果没有任何一种组合,则返回-1
示例:
输入:coins=[1,2,5],amount = 11
输出:3
解释:11= 5+5+1
思路:
这个问题可以看成爬楼梯的翻版,在某一个台阶上可以往上走1步,2步和5步,走到对应的台阶数各种最少需要多少步
解题步骤:
-
定义状态:组成第i个面值需要最少的硬币个数dp[i]
-
定义状态方程:dp[i] = min(dp[i-1], dp[i-2],dp[i-5]),这里的1,2,5是硬币面值
public static int algorithm(int[] coins, int amount) {
// 定义一个数组,长度为amount+1
int[] dp = new int[amount + 1];
// 填充上比较大的数字
Arrays.fill(dp, Integer.MAX_VALUE);dp[0] = 0; // 遍历获取每一个面值所需的最少硬币数 for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.length; j++) { if (coins[j] <= i) { // 根据状态方程计算每一步所需最少硬币数,这里注意+1放在括号里 dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } } return (dp[amount] > amount) ? -1 : dp[amount];
}
3.2 给定两个单词word1和word2,计算出将word1转换成word2所使用的最少操作数
可以做如下操作:
-
插入一个字符
-
删除一个字符
-
替换一个字符
示例: 输入:word1=“horse”,word2=“ros” 输出:3
解题步骤:
- 定义状态:dp[i][j]表示第一个单词的前i个字符转换为第二个单词的前j个字符最少步数
- 状态转移方程
-
word1[i] == word2[j],两个字符一样,则不需要额外的操作,dp[i][j] = dp[i-1][j-1]
-
如果两个字符不一样,那么最小步数为:增删改的步骤 1 + 原步骤的最小值dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]),此处不太好理解,如果画出二维表格推演一下,就能得出这个结论。
public static int minDistance(String word1, String word2) { int[][] dp = new int[word1.length() + 1][word2.length() + 1]; // 网格的两个边都只能添加字符 for (int i = 0; i < dp.length; i++) { dp[i][0] = i; } for (int i = 0; i < dp[0].length; i++) { dp[0][i] = i; } for (int i = 1; i < dp.length; i++) { for (int j = 1; j < dp[0].length; j++) { int left = dp[i - 1][j]; int up = dp[i][j - 1]; int left_up = dp[i - 1][j - 1]; if (word1.charAt(i - 1) == word2.charAt(j - 1)) //当前字符一样,不需要操作 dp[i][j] = left_up; else // 字符不一样,找最小值+1 dp[i][j] = 1 + Math.min(left, Math.min(up, left_up)); } } return dp[dp.length - 1][dp[0].length - 1]; }
-