[LintCode] Edit Distance

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

  • Insert a character
  • Delete a character
  • Replace a character
Example

Given word1 = "mart" and word2 = "karma", return 3.

 

Solution 1. Recursion 

i is the last character's index in word1, j is the last character's index in word2.

Recursive functions:

f(i, j) = Math.min(1 + Math.min(f (i - 1, j), f(i, j - 1) ),   f(i - 1, j - 1)),  if word1.charAt(i) == word2.charAt(j);

f(i, j) = Math.min(1 + Math.min(f (i - 1, j), f(i, j - 1) ),   1 + f(i - 1, j - 1)), if word1.charAt(i) != word2.charAt(j);

 

Base case:

i < 0 && j < 0: both words are empty, no operations is needed;

i < 0 && j >= 0: word1 empty but word2 not empty, j + 1 deletions is needed;

i >= 0 && j < 0: word1 not empty word2 empty, i + 1 deletions is needed;

 

 1 public class Solution {
 2     public int minDistance(String word1, String word2) {
 3         if(word1 == null || word2 == null){
 4             return Integer.MAX_VALUE;
 5         }
 6         return helper(word1, word1.length() - 1, word2, word2.length() - 1);
 7     }
 8     private int helper(String word1, int idx1, String word2, int idx2){
 9         if(idx1 < 0 && idx2 < 0){
10             return 0;
11         }
12         else if(idx1 < 0){
13             return idx2 + 1;
14         }
15         else if(idx2 < 0){
16             return idx1 + 1;
17         }
18         if(word1.charAt(idx1) == word2.charAt(idx2)){
19             return Math.min(1 + Math.min(helper(word1, idx1- 1, word2, idx2), helper(word1, idx1, word2, idx2 - 1)), helper(word1, idx1 - 1, word2, idx2 - 1));
20         }
21         return Math.min(1 + Math.min(helper(word1, idx1- 1, word2, idx2), helper(word1, idx1, word2, idx2 - 1)), 1 + helper(word1, idx1 - 1, word2, idx2 - 1));
22     }
23 }

 

Solution 2. Top down DFS search with Memoization, (Dynamic Programming in essence)

Solution 1 does a lot of duplicate work by computing answers of the same subproblems over and over.

Caching subproblems' results with memoization optimizes on solution 1. 

 

 1 public class Solution {
 2     private int[][] T;
 3     public int minDistance(String word1, String word2) {
 4         if(word1 == null || word2 == null){
 5             return Integer.MAX_VALUE;
 6         }
 7         T = new int[word1.length()][word2.length()]; 
 8         for(int i = 0; i < word1.length(); i++){
 9             for(int j = 0; j < word2.length(); j++){
10                 T[i][j] = Integer.MAX_VALUE;
11             }
12         }
13         return helper(word1, word1.length() - 1, word2, word2.length() - 1);
14     }
15     private int helper(String word1, int idx1, String word2, int idx2){
16         if(idx1 < 0 && idx2 < 0){
17             return 0;
18         }
19         else if(idx1 < 0){
20             return idx2 + 1;
21         }
22         else if(idx2 < 0){
23             return idx1 + 1;
24         }
25         if(T[idx1][idx2] != Integer.MAX_VALUE){
26             return T[idx1][idx2];
27         }
28         int r = Integer.MAX_VALUE;
29         if(word1.charAt(idx1) == word2.charAt(idx2)){
30             r = Math.min(1 + Math.min(helper(word1, idx1- 1, word2, idx2), helper(word1, idx1, word2, idx2 - 1)), helper(word1, idx1 - 1, word2, idx2 - 1));
31         }
32         else{
33             r = Math.min(1 + Math.min(helper(word1, idx1- 1, word2, idx2), helper(word1, idx1, word2, idx2 - 1)), 1 + helper(word1, idx1 - 1, word2, idx2 - 1));            
34         }
35         T[idx1][idx2] = r;
36         return r;
37     }
38 }

 

Solution 3. Bottom up dynamic programming

State functions are derived directly from the above recursive solution. 

dp[i][j]: the minimum number of operations needed to covert word1's first ith characters to word2's first jth characters.

Function: 

if(word1.charAt(i - 1) == word2.charAt(j - 1)){
    dp[i][j] = Math.min(1 + Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
}
else{
    dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
}

  

Initializations:

dp[i][0]: delete a character from word1 i times;

dp[0][j]: insert a character to word1 j times;

 

 1 public class Solution {
 2     public int minDistance(String word1, String word2) {
 3         if(word1 == null || word2 == null){
 4             return Integer.MAX_VALUE;
 5         }
 6         int[][] dp = new int[word1.length() + 1][word2.length() + 1];
 7         dp[0][0] = 0;
 8         for(int i = 1; i <= word1.length(); i++){
 9             dp[i][0] = i;
10         }
11         for(int j = 1; j <= word2.length(); j++){
12             dp[0][j] = j;
13         }
14         for(int i = 1; i <= word1.length(); i++){
15             for(int j = 1; j <= word2.length(); j++){
16                 if(word1.charAt(i - 1) == word2.charAt(j - 1)){
17                     dp[i][j] = Math.min(1 + Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
18                 }
19                 else{
20                     dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]);
21                 }
22             }
23         }
24         return dp[word1.length()][word2.length()];
25     }
26 }

 

Related Problems

Edit Distance II

 

posted @ 2017-06-20 05:26  Review->Improve  阅读(228)  评论(0编辑  收藏  举报