编辑距离总结

1.编辑距离

动态规划思路(自底向上)

这道题其实和前面的两个字符删除操作极其的相似,只不过是状态需要好好地捋清楚。

  • dp[i] [j]这里的i的意思就是word1前i个字符,word2前j个字符,如果要把word1改成word2所需要的最少操作。这里的把word1改成word2非常重要,必须理清楚关系是word1改成word2,重要的事说三遍。知道这个之后后面的状态转移才有可能捋清楚

  • 如果word1[i]==word[j]那么就可以什么都不做

  • 如果不相等就会有三种情况

  1. dp[i] [j]=dp[i] [j-1]+1

    第一种就是直接插入,那么插入的位置自然就是word1,前i个不需要做任何改变只需要插入一个与word2的j相同的字符就好了。那么这个时候就需要取dp[i] [j-1]因为word1前i个没有变化,相当于就只是在后面插入一个,那么为什么是j-1?思考一下现在相同的是word2的第j个字符,而且word1通过在i后面插入一个新字符和word2的第j个字符相同,那么问题就是它的子问题到底是什么。子问题其实就是去掉j和新插入的字符之后的字符串状态就是用于递推当前状态的子问题,所以就是去掉j,去掉新插入不就是dp[i] [j-1]吗

  2. dp[i] [j-1]=dp[i-1] [j]+1

    第二个就是删除状态,那么删除肯定就是直接把第i个字符删除掉,那么才能够让上一次的前i-1的word1和前j的word2字符串相同(已经经过修改并且须选出最少的操作)。获取到dp[i] [j]的办法删除了i,相当于状态就是少了i的时候的状态的最少操作数+1然后推出当前期的

  3. dp[i] [j] =dp[i-1] [j-1]+1

    这种就是直接进行替换操作,这种是最好理解的。直接换

  • 可能会有一个问题,你怎么知道前面都已经修改好了。首先是你要知道基础状态的修改已经定义好
  • for(int i=0;i<=len1;i++) dp[i] [0]=i;如果有i个字符串修改为空串那么肯定都是全部删除才能是空串
    for(int j=0;j<=len2;j++) dp[0] [j]=j;如果是空串修改为j那么肯定就是不断地插入就好了。中间如果修改很明显就不是最小的操作数
  • 也就是说从基础状态推过来的都是已经修改好的了
class Solution {
    public int minDistance(String word1, String word2) {
         int len1=word1.length();
         int len2=word2.length();
         int[][] dp=new int[len1+1][len2+1];
         for(int i=0;i<=len1;i++) dp[i][0]=i;
         for(int j=0;j<=len2;j++) dp[0][j]=j;
         
         for(int i=1;i<=len1;i++){
             for(int j=1;j<=len2;j++){
                 if(word1.charAt(i-1)==word2.charAt(j-1)){
                     dp[i][j]=dp[i-1][j-1];
                 }else{
                     dp[i][j]=Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i][j-1]))+1;
                 }
             }
         }
         return dp[len1][len2];
    }
}

自顶向下的动态规划(记忆搜索)思路

这种其实如果第一种思考清楚那么这种只不过就是推一推就好了,本质就是树和选择的问题。如果相等就是只有一个分支,如果是不相等那么就是三个分支,相当于就是三叉树了。这种看上去很复杂但是框架确是比较清晰的。分析和上面的基本上是一样的,加上了备忘录。

class Solution {
    int[][] res;
    int max=Integer.MAX_VALUE;
    public int minDistance(String word1, String word2) {
         int len1=word1.length();
         int len2=word2.length();
         res=new int[len1+1][len2+1];
         
         for(int i=0;i<=len1;i++) res[i][0]=i;
         for(int j=0;j<=len2;j++) res[0][j]=j;

         for(int i=1;i<=len1;i++){
             for(int j=1;j<=len2;j++){
                 res[i][j]=max;
             }
         } 

         return solve(len1,len2,word1,word2);
    }
    
    public int solve(int str1,int str2,String word1,String word2){
        if(str1==0) return str2;
        
        if(str2==0) return str1;
        
        if(res[str1][str2]<max){
            return res[str1][str2];
        }

        if(word1.charAt(str1-1)==word2.charAt(str2-1)){
               int minOps=res[str1][str2]=solve(str1-1,str2-1,word1,word2);
               return minOps;
        }else{
               int minOps=Math.min(solve(str1-1,str2-1,word1,word2),
               Math.min(solve(str1-1,str2,word1,word2),solve(str1,str2-1,word1,word2)))+1;
               res[str1][str2]=minOps;
               return minOps;
        }

        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值