解法1:暴力递归
对于给定的单词 A 和 B,从左向右逐个匹配:
①对于 A 中当前遍历到的字符 A[i],如果和 B[j] 相同,则不需要任何操作,继续向右遍历 i+1, j+1
②如果 A[i] != B[j],则可以删除 A[i],或者替换 A[i],或者插入和 B[j] 相同的字符,因此存在三种选项
所以每次遍历匹配时,都存在 4 种可能的逻辑分支,设函数为dfs
- A[i] == B[j]
dfs(str1,i+1,str2,j+1,ic,dc,rc),i+1和j+1继续比较 - A[i] != B[j]
dfs(str1,i,str2,j+1,ic,dc,rc)+ic 说明str1中在i前插入一个元素,i和j+1继续比较
dfs(str1,i+1,str2,j+1,ic,dc,rc)+rc说明str1中i处元素被替换,i+1和j+1继续比较
dfs(str1,i+1,str2,j,ic,dc,rc)+dc说明str1中i处元素被删除,i+1和j继续比较
//复杂度比较大,运行超时 public static int minEditCost (String str1, String str2, int ic, int dc, int rc) { return dfs(str1,0,str2,0,ic,dc,rc); } public static int dfs (String str1, int i, String str2, int j,int ic, int dc, int rc) { if(i==str1.length()){ return (str2.length()-j)*ic; } if(j==str2.length()){ return (str1.length()-i)*dc; } if(str1.charAt(i)==str2.charAt(j)){ return dfs(str1,i+1,str2,j+1,ic,dc,rc); } return Math.min(dfs(str1,i,str2,j+1,ic,dc,rc)+ic, Math.min(dfs(str1,i+1,str2,j+1,ic,dc,rc)+rc, dfs(str1,i+1,str2,j,ic,dc,rc)+dc)); }
解法1:动态规划
- dp[i][j]表示word1的前i个字符编辑成word2的前j个字符需要的最小操作数
- 初始状态:dp[i][0] = i,i次删除;dp[0][i] = i,i次插入
- 状态转移方程:
- 当i字符等于j字符时:dp[i][j] = dp[i-1][j-1],不需要额外操作
- 当i字符不等于j字符时:dp[i][j] = Math.min(insert, delete, replace)
①int insert = dp[i][j-1] + 1; i个编辑成j-1个字符,再插入一个j
②int delete = dp[i-1][j] + 1; i-1个编辑成j个字母,再删除一个i
③int replace = dp[i-1][j-1] + 1; i-1个编辑成j-1个字母,再将i替换成jpublic int minEditCost (String str1, String str2, int ic, int dc, int rc) { // write code here int m = str1.length(); int n = str2.length(); int[][] dp = new int[m+1][n+1]; for(int i = 1; i <= m; i++) { dp[i][0] = i*dc; } for(int j = 1; j <= n; j++) { dp[0][j] = j*ic; } for(int i = 1; i <= m; i++) { char c1 = str1.charAt(i-1); for(int j = 1; j <= n; j++) { char c2 = str2.charAt(j-1); if(c1 == c2) { dp[i][j] = dp[i-1][j-1]; } else { int insert = dp[i][j-1] + ic; int delete = dp[i-1][j] + dc; int replace = dp[i-1][j-1] + rc; dp[i][j] = Math.min(replace, Math.min(insert, delete)); } } } return dp[m][n]; }