2つの単語間の距離を編集する

参照ブログ:https//github.com/youngwind/blog/issues/106

2つの単語word1とword2が与えられた場合、word1をword2に変換するために使用されるオペランドの最小数を計算します。

ワードに対して次の3つの操作を実行できます。

文字
挿入する文字を削除する文字を
置き換える
例1:

入力:word1 = "horse"、word2 = "ros"
出力:3
説明:
horse-> rorse( '
h 'を 'r'に置き換えます)rorse-> rose(delete'r ')rose-
> ros(delete'e ')

出典:LeetCode
リンク:https ://leetcode-cn.com/problems/edit-distance
著作権はLeetCodeが所有しています商用の再版については、公式の承認に連絡してください。非商用の再版については、出典を示してください。

与えられた2つの単語に対して、最も少ないステップでword1をword2に変換する方法は?インターネットでいくつかの解決策を学びました。再帰的および動的プログラミングの場合、2つの方法は異なる方法で実装されますが、基本的な考え方は同じです。アイデアは次のとおりです
。2つの単語について、ある単語を別の単語に変換する場合は、単語の各文字を考慮して、他の単語の各文字と同じにする必要があります。つまり、対応する編集を行います。 2つの文字が同じ場合は、順番に編集する必要がある他の文字を編集します

  • d [i] [j]が、word1の長さiの部分文字列からword2の長さjの部分文字列までの最小および最小編集距離を表すとします。
  • iとjがそれぞれ対応する文字列の長さに等しい場合、つまり、d [word1.lenggth()] [word2.length()]が必要です。
  • 長さiと長さjの部分文字列の場合、2つの部分文字列の最後の文字が等しい場合、つまり、word1.charAt(i-1)== word2.charAt(j-1)の
    場合、2つの部分文字列の編集距離d [i] [j] = d [i-1] [j-1]、これは長さi-1および長さj-1の部分文字列の編集距離に等しい。これは同じであるため理解しやすい。編集する必要はありません。
  • 2つの部分文字列の最後の文字が等しくない場合、つまり、word1.charAt(i-1)!= word2.charAt(j-1)、現時点ではそれに応じて編集する必要があります、
  • 編集方法1:d [i] [j] = d [i] [j-1] + 1
  • :文字列abcとacdの場合、2つの文字列の最後の文字が等しくありません。
  • :文字を追加できます。dを追加すると、abcがabcdになります。
  • :abcdからacdまでの脚本距離は、abcからacまでの編集距離と同じです。これは、dが等しいため、つまり、d [i] [j] = d [i] [j-1] + 1
  • :実際、ここに文字を追加すると、acdの文字dを削除するのと同じ効果があります。
  • 編集方法2:d [i] [j] = d [i-1] [j] + 1
  • :文字cを追加すると、acdはacdcになります
  • :abcからacdへの編集距離は、cが等しいため、abからacdへの編集距離になります。つまり、d [i] [j] = d [i-1] [j] + 1
  • :ここで文字cを追加する方法は、abcで文字cを削除する方法と同じです。
  • 編集方法3:d [i] [j] = d [i-1] [j-1] + 1
  • :文字を置き換えることで、abcの最後の文字をdに置き換えることができます。つまり、abdをacdに置き換えることができます(abcをaccに置き換えることもできます)
  • :対応する編集距離は次のようになります。d[i] [j [] = d [i -1] [j-1] +1
    上記の3つの変換方法では、3つの最小値を使用して、対応する最小編集距離を取得します。

ソリューションのコーディングの過程で

  • 動的計画法の場合、対応する初期値を与える必要があります。
  • 再帰的方法の場合、境界値を与える必要があります
class 编辑距离 {
    
    

 //递归解法  
     public static int minDistanceWay1(String word1, String word2) {
    
    
     // 减少重复运算,不然会超时
        int[][] dis = new int[word1.length() + 1][word2.length() + 1];
        for (int i = 0; i <= word1.length(); i++) {
    
    
            Arrays.fill(dis[i], -1);
        }
        return recursion(word1, word2, word1.length(), word2.length(), dis);
    }

    private static int recursion(String word1, String word2, int length1, int length2, int[][] dis) {
    
    
        if (dis[length1][length2] > -1) {
    
    
            return dis[length1][length2];
        }
        if (length1 == 0) {
    
    
            return length2;
        } else if (length2 == 0) {
    
    
            return length1;
        } else if (word1.charAt(length1 - 1) == word2.charAt(length2 - 1)) {
    
    
            // 两个字符相等的话我们就直接比较前一个字符
            int distance = recursion(word1, word2, length1 - 1, length2 - 1, dis);
            dis[length1][length2] = distance;
            return distance;
        } else {
    
    
            // 删除字符和添加字符我们达到的效果是一样的
            // 当两个字符串不相等的时候我们就删除word1的最后一个字符,计算(m-1,n)这两个字符串之间的最短编辑距离
            int deleteWord1 = recursion(word1, word2, length1 - 1, length2, dis);
            // 删除word2的最后一个字符
            int deleteWord2 = recursion(word1, word2, length1, length2 - 1, dis) + 1;
            // 替换一个word1或者word2中的任意一个字符
            int replaceWord = recursion(word1, word2, length1 - 1, length2 - 1, dis);
            int distance = Math.min(Math.min(deleteWord1, deleteWord2), replaceWord) + 1;
            dis[length1][length2] = distance + 1;
            return distance;
        }
    }

//  动态规划解法
    public static int minDistanceWay2(String word1, String word2) {
    
    
        int lenWord1 = word1.length();
        int lenword2 = word2.length();
        // minDis[i][j]表示长度为i和长度为j的单词之间的最小编辑距离
        int[][] minDis = new int[lenWord1 + 1][lenword2 + 1];
        for (int i = 1; i <= lenWord1; i++) {
    
    
            minDis[i][0] = i;
        }

        for (int j = 1; j <= lenword2; j++) {
    
    
            minDis[0][j] = j;
        }

        for (int i = 1; i <= lenWord1; i++) {
    
    
            for (int j = 1; j <= lenword2; j++) {
    
    
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
    
    
                    minDis[i][j] = minDis[i - 1][j - 1];
                } else {
    
    
                    int deleteWord1 = minDis[i - 1][j] + 1;
                    int deleteWord2 = minDis[i][j - 1] + 1;
                    int replaceWord = minDis[i - 1][j - 1] + 1;
                    minDis[i][j] = Math.min(Math.min(deleteWord1, deleteWord2), replaceWord);
                }
            }
        }
        return minDis[word1.length()][word2.length()];
    }

    public static void main(String[] args) {
    
    
        System.out.println(minDistanceWay2("b", ""));
        System.out.println(minDistanceWay2("dinitrophenylhydrazine", "benzalphenylhydrazone"));
    }
}```

おすすめ

転載: blog.csdn.net/liu_12345_liu/article/details/102533541