最小编辑距离

编辑距离

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)

dp[i][j]
dp[i + 1][j] (删除操作)
dp[i][j + 1] (新增操作)
dp[i + 1][j + 1] + incre (替换操作)

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();
    }
}

结果:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值