【题目6】编辑距离

可以对一个字符串进行三种操作:插入一个字符、删除一个字符、替换一个字符

给定2个字符串s1和s2,计算将s1转换为s2最少需要多少次操作,并打印出具体操作。

【举例】

s1 = "intention",s2 = "execution",输出:

Change s1=intention to s2=execution:

s1[8]:skip 'n'
s1[7]:skip 'o'
s1[6]:skip 'i'
s1[5]:skip 't'
s1[4]:insert 'u'
s1[4]:replace 'n'with 'c'
s1[3]:skip 'e'
s1[2]:delete 't'
s1[1]:replace 'n'with 'x'
s1[0]:replace 'i'with 'e'
5

public class Code06_MinDistance {
    public static class Node {
        public int val;
        public int choice;// 0代表啥都不做,1代表插入,2代表删除,3代表替换

        public Node(int val, int choice) {
            this.val = val;
            this.choice = choice;
        }
    }

    public static int minDistance(String s1, String s2) {
        int m = s1.length();
        int n = s2.length();
        // dp[i][j]--s1[0...i-1]和s2[0...j-1]的最小编辑距离
        Node[][] dp = new Node[m + 1][n + 1];
        dp[0][0] = new Node(0, 0);// 别忘记初始化dp[0][0],否则会报空指针使用问题!!!!!!!
        for (int i = 1; i <= m; i++) {
            dp[i][0] = new Node(i, 2);
        }
        for (int i = 1; i <= n; i++) {
            dp[0][i] = new Node(i, 1);
        }
        // dp[i - 1][j]#删除-2dp[i][j - 1]#插入1-dp[i - 1][j - 1]#替换3
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {// 这里没用转换成char数组
                    Node node = dp[i - 1][j - 1];
                    dp[i][j] = new Node(node.val, 0);

                } else {
                    dp[i][j] = minNode(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
                    dp[i][j].val++;
                }
            }
        }
        printResult(dp, s1, s2);
        return dp[m][n].val;
    }

    private static void printResult(Node[][] dp, String s1, String s2) {
        int rows = dp.length;
        int cols = dp[0].length;
        int i = rows - 1, j = cols - 1;
        System.out.println("Change s1=" + s1 + " to s2=" + s2 + ":\n");
        while (i != 0 && j != 0) {
            char c1 = s1.charAt(i - 1);
            char c2 = s2.charAt(j - 1);
            int choice = dp[i][j].choice;
            System.out.print("s1[" + (i - 1) + "]:");
            switch (choice) {
            case 0:
                System.out.println("skip '" + c1 + "'");
                i--;
                j--;
                break;
            case 1:
                System.out.println("insert '" + c2 + "'");
                j--;
                break;
            case 2:
                System.out.println("delete '" + c1 + "'");
                i--;
                break;
            case 3:
                System.out.println("replace '" + c1 + "'" + "with '" + c2 + "'");
                i--;
                j--;
                break;
            }
        }
        while (i > 0) {
            System.out.print("s1[" + (i - 1) + "]:");
            System.out.println("delete '" + s1.charAt(i - 1) + "'");
            i--;
        }
        while (j > 0) {
            System.out.print("s1[0]:");
            System.out.println("insert '" + s2.charAt(j - 1) + "'");
            j--;
        }
    }

    private static Node minNode(Node a, Node b, Node c) {
        Node res = new Node(a.val, 2);
        if (res.val > b.val) {
            res.val = b.val;
            res.choice = 1;
        }
        if (res.val > c.val) {
            res.val = c.val;
            res.choice = 3;
        }
        return res;
    }

    public static void main(String[] args) {
        String s1 = "intention";
        String s2 = "execution";
        System.out.println(minDistance(s1, s2));
    }
}