左神算法 最小编辑代价
2018-01-29 17:16
232 查看
【题目】
给定两个字符串str1和str2,在给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,返回将str1编辑成str2的最小代价
【举例】str1 = “abc”
str2 = “adc”,ic = 5, dc=3,rc=2
【1】从abc编辑成adc,把b替换成d代价是最小的,返回2
【2】如果rc =100,先删除b,再插入d代价是最小的,返回8
【3】如果str1 == str2 说明不用修改,返回0
用动态规划解题
m = str1.length(), n = str2.length()
申请dp,行数是m+1,列数是n+1。这里我规定str1是行,str2是列。
dp[i][j]代表str1的下标是0….i-1个字符 和 str2的下标是0….j-1字符的最小编辑代价。
如果申请的行列数还是字符串的长度,不加一行做空字符串匹配。那么在还是按之前的动态规划方法做的时候会发现问题,第一行和第一列很难确定它的值。因为有多种选择,第一行有一个str1中的第一个字符了,这时候是选择替换,删除,还是增加呢。状态不好确定。
所以第一行从空字符开始,对于dp[0][j]表示str1还是空串的时候,它去匹配str2的str2[0,1….j-1]字符串,很明显,只有添加的情况,dp[0][j]就是一个等差数列。
同理,第一列就是只有删除的情况。
从dp[1][1]开始填表,dp[i][j]的状态取决于斜上格,左格,和上格。
【犯错】这里我犯了一个错误。
在计算dp[i][j]的时候,在状态转移中如果str1[i-1]和str2[j-1]的字符相等,dp[i][j] = dp[i-1][j-1],这里我认为只有这种情况了。其实是错误的,还是要和左格和上格比较,取最小值。在这题中,我不能保证dp[i-1][j-1]<= dp[i-1][j]和dp[i-1][j-1]<=dp[i][j-1],这两个公式是不能保证成立的。因为dp[i][j-1]也可能从它的斜上方迁跃过来。从图中也可以看到这个公式是不成立的,请看第5行第6列的值4,小于它的左边5。
所以如果相等,还是要继续做比较,我下面的代码就是有问题的。
【问题代码】
【状态转移】
这里再说明下状态转移,就有三种情况,dp[i][j]:
【1】dp[i][j-1] + ic ,这是str1的当前子串和str2当前子串的最后一个字符之前的子串调整后匹配了,又多了一个str2的字符,为了匹配上,得插入,代价是ic。
【2】dp[i-1][j] + dc ,str1的当前子串的最后一个字符之前的子串和str2当前子串匹配了, 这是str1又多了一个字符,为了匹配上,得删除,代价是dc
【2】dp[i-1][j-1] + rc,str1的当前子串的最后一个字符之前的子串和str2当前子串的最后一个字符之前的子串匹配了,如果str1当前子串的最后一个字符和str2当前子串的最后一个字符不相等,就得加上rc。如果相等,就是dp[i-1][j-1]
【正确代码如下】、
给定两个字符串str1和str2,在给定三个整数ic,dc和rc,分别代表插入、删除和替换一个字符的代价,返回将str1编辑成str2的最小代价
【举例】str1 = “abc”
str2 = “adc”,ic = 5, dc=3,rc=2
【1】从abc编辑成adc,把b替换成d代价是最小的,返回2
【2】如果rc =100,先删除b,再插入d代价是最小的,返回8
【3】如果str1 == str2 说明不用修改,返回0
用动态规划解题
m = str1.length(), n = str2.length()
申请dp,行数是m+1,列数是n+1。这里我规定str1是行,str2是列。
dp[i][j]代表str1的下标是0….i-1个字符 和 str2的下标是0….j-1字符的最小编辑代价。
如果申请的行列数还是字符串的长度,不加一行做空字符串匹配。那么在还是按之前的动态规划方法做的时候会发现问题,第一行和第一列很难确定它的值。因为有多种选择,第一行有一个str1中的第一个字符了,这时候是选择替换,删除,还是增加呢。状态不好确定。
所以第一行从空字符开始,对于dp[0][j]表示str1还是空串的时候,它去匹配str2的str2[0,1….j-1]字符串,很明显,只有添加的情况,dp[0][j]就是一个等差数列。
同理,第一列就是只有删除的情况。
从dp[1][1]开始填表,dp[i][j]的状态取决于斜上格,左格,和上格。
【犯错】这里我犯了一个错误。
在计算dp[i][j]的时候,在状态转移中如果str1[i-1]和str2[j-1]的字符相等,dp[i][j] = dp[i-1][j-1],这里我认为只有这种情况了。其实是错误的,还是要和左格和上格比较,取最小值。在这题中,我不能保证dp[i-1][j-1]<= dp[i-1][j]和dp[i-1][j-1]<=dp[i][j-1],这两个公式是不能保证成立的。因为dp[i][j-1]也可能从它的斜上方迁跃过来。从图中也可以看到这个公式是不成立的,请看第5行第6列的值4,小于它的左边5。
所以如果相等,还是要继续做比较,我下面的代码就是有问题的。
【问题代码】
public class Main { public static void main(String[] args) { String str1 = "ab12cd3"; String str2 = "abcdf"; int ic = 5, dc = 3, rc =2; System.out.println(minCost(str1, str2, ic, dc, rc)); } public static int minCost(String str1, String str2, int ic, int dc, int rc){ if (str1 == null ||str2 == null || str1.length() == 0 ||str2.length() == 0){ return 0; } int[][] dp = new int[str1.length() + 1][str2.length() + 1]; for (int i = 1; i <= str2.length(); i++) { dp[0][i] = dp[0][i-1] + ic; } for (int i = 1; i <= str1.length() ; i++) { dp[i][0] = dp[i-1][0] + dc; } for (int i = 1; i <=str1.length() ; i++) { for (int j = 1; j <= str2.length(); j++) { if (str1.charAt(i-1) == str2.charAt(j-1)){ dp[i][j] = dp[i-1][j-1]; } else { dp[i][j] = Math.min(dp[i-1][j-1] + rc, Math.min(dp[i][j-1] + ic, dp[i-1][j] + dc)); } } } return dp[str1.length()][str2.length()]; } }
【状态转移】
这里再说明下状态转移,就有三种情况,dp[i][j]:
【1】dp[i][j-1] + ic ,这是str1的当前子串和str2当前子串的最后一个字符之前的子串调整后匹配了,又多了一个str2的字符,为了匹配上,得插入,代价是ic。
【2】dp[i-1][j] + dc ,str1的当前子串的最后一个字符之前的子串和str2当前子串匹配了, 这是str1又多了一个字符,为了匹配上,得删除,代价是dc
【2】dp[i-1][j-1] + rc,str1的当前子串的最后一个字符之前的子串和str2当前子串的最后一个字符之前的子串匹配了,如果str1当前子串的最后一个字符和str2当前子串的最后一个字符不相等,就得加上rc。如果相等,就是dp[i-1][j-1]
【正确代码如下】、
public class Main { public static void main(String[] args) { String str1 = "ab12cd3"; String str2 = "abcdf"; int ic = 5, dc = 3, rc =2; System.out.println(minCost(str1, str2, ic, dc, rc)); } public static int minCost(String str1, String str2, int ic, int dc, int rc){ if (str1 == null ||str2 == null || str1.length() == 0 ||str2.length() == 0){ return 0; } int[][] dp = new int[str1.length() + 1][str2.length() + 1]; for (int i = 1; i <= str2.length(); i++) { dp[0][i] = dp[0][i-1] + ic; } for (int i = 1; i <= str1.length() ; i++) { dp[i][0] = dp[i-1][0] + dc; } for (int i = 1; i <=str1.length() ; i++) { for (int j = 1; j < 4000 = str2.length(); j++) { if (str1.charAt(i-1) == str2.charAt(j-1)){ dp[i][j] = dp[i-1][j-1]; } else { dp[i][j] = dp[i-1][j-1] +rc; //修改之处 } dp[i][j] = Math.min(dp[i][j], Math.min(dp[i][j-1] + ic, dp[i-1][j] + dc)); //修改之处 } } return dp[str1.length()][str2.length()]; } }
相关文章推荐
- 最小编辑代价
- 最长公共子序列与最小编辑距离-你有更快的算法么?
- 最小编辑代价
- 利用最小编辑距离算法实现文本diff
- 动态规划系列问题-最小编辑代价
- 最小编辑代价---动态规划
- 最小编辑代价
- Levenshtein distance最小编辑距离算法实现
- 最小编辑代价(动态规划)
- Levenshtein distance最小编辑距离算法实现
- 算法爱好者——算法题:最小调整代价 ? 待解决
- 最小编辑代价(动态规划)
- 最小编辑代价&&华为OJ 编辑距离&&计算字符串的相似度
- 递归与动态规划---最小编辑代价
- 最小编辑代价
- 最小编辑代价 动态规划
- 最小编辑代价
- 最小编辑代价(动态规划)
- #牛客#代码实现:最小编辑代价、最长增长子序列、汉诺塔进阶、单链表相交
- 最小编辑代价