72
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/edit-distance
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
通过动态规划求解
设 dp[i][j] 为a.substring(i) 和 b.substring(j) 两个子串之间的编辑距离
则有状态转换方程如下: (如果 i 和 j 位置字符一致 看作特殊的替换操作
incre 为 0 否则为 1)
1. 求解
代码:
class Solution {
public int minDistance(String word1, String word2) {
int l1 = word1.length(); int l2 = word2.length();
if (l1 == 0) {
return l2;
}
if (l2 == 0) {
return l1;
}
int [][] dp = new int[l1 + 1][];
for (int i = 0; i <= l1; i++) {
dp[i] = new int[l2 + 1];
if (i != l1) {
dp[i][l2] = l1 - i;
}
}
for (int j = 0; j < l2; j ++) {
dp[l1][j] = l2 - j ;
}
dp[l1][l2] = 0;
for (int i = l1 - 1; i >= 0; i--) {
for (int j = l2 - 1; j >= 0; j--) {
int hex = word1.charAt(i) == word2.charAt(j) ? 0 : 1;
int min = dp[i + 1][j + 1] + hex;
min = Math.min(min, dp[i + 1][j] + 1);
min = Math.min(min, dp[i][j+ 1] + 1);
dp[i][j] = min;
}
}
return dp[0][0];
}
}
2. 打印移动方法
在做状态选择时记录下链路 结束时回溯一下
package com.leetcode.siwei;
import java.util.*;
public class BianjiJuLi {
enum OpType {
ADD,
DEL,
RP,
JUST_MOVE,
;
}
class Point {
int i; int j;
public Point() {}
public Point(int i, int j) {
this.i = i; this.j = j;
}
public OpType getOpType(Point p, boolean equal) {
if (p.i > this.i && p.j > this.j) {
return equal ? OpType.JUST_MOVE : OpType.RP;
} else if (p.i == this.i) {
return OpType.ADD;
}
return OpType.DEL;
}
@Override
public int hashCode() {
return (i + ":" + j).hashCode();
}
@Override
public boolean equals(Object other) {
if (other == null || other.getClass() != Point.class) {
return false;
}
Point o = (Point) other;
return this.i == o.i && this.j == o.j;
}
}
private Map<Point, Point> map = new HashMap<>();
private String one;
private String two;
public int minDistance(String word1, String word2) {
map = new HashMap<>();
this.one = word1; this.two = word2;
int l1 = word1.length(); int l2 = word2.length();
if (l1 == 0) {
return l2;
}
if (l2 == 0) {
return l1;
}
int [][] dp = new int[l1 + 1][];
for (int i = 0; i <= l1; i++) {
dp[i] = new int[l2 + 1];
if (i != l1) {
dp[i][l2] = l1 - i;
}
}
for (int j = 0; j < l2; j ++) {
dp[l1][j] = l2 - j ;
}
dp[l1][l2] = 0;
for (int i = l1 - 1; i >= 0; i--) {
for (int j = l2 - 1; j >= 0; j--) {
int hex = word1.charAt(i) == word2.charAt(j) ? 0 : 1;
int min = dp[i + 1][j + 1] + hex;
int last = min;
Point curr = new Point(i, j);
map.put(curr, new Point(i + 1, j + 1));
min = Math.min(min, dp[i + 1][j] + 1);
if (min != last) {
map.put(curr, new Point(i + 1, j));
last = min;
}
min = Math.min(min, dp[i][j+ 1] + 1);
if (min != last) {
map.put(curr, new Point(i, j + 1));
}
dp[i][j] = min;
}
}
return dp[0][0];
}
public void output() {
System.out.println("start");
Point start = new Point(0, 0);
List<Point> ops = new ArrayList<>();
ops.add(start);
while ((start = map.get(start)) != null) {
ops.add(start);
}
boolean end = false;
for (int i = 0; i < ops.size() - 1; i++) {
start = ops.get(i);
OpType opType = ops.get(i).getOpType(ops.get(i + 1), one.charAt(start.i) == two.charAt(start.j));
String text = "";
switch (opType) {
case JUST_MOVE:
text = "just move";
end = true;
break;
case ADD:
text = "新增字符: " + two.charAt(start.j);
break;
case DEL:
text = "删除字符: " + one.charAt(start.i);
break;
case RP:
text = String.format("替换字符: %s -> %s", one.charAt(start.i), two.charAt(start.j));
end = true;
break;
default:
break;
}
System.out.println(text);
}
Point last = ops.get(ops.size() - 1);
if (last.i >= one.length() && last.j >= two.length()) {
return;
}
if (last.i >= one.length()) {
for (int j = last.j; j < two.length(); j ++) {
System.out.println("新增字符: " + two.charAt(j));
}
} else if (last.j >= two.length()){
for (int i = last.i; i < one.length(); i++) {
System.out.println("删除字符: " + one.charAt(i));
}
}
}
public static void main(String[] args) {
BianjiJuLi a = new BianjiJuLi();
a.minDistance("horse", "ros");
a.output();
}
}
结果: