Convert a string to another string in the shortest path

时间:2016-04-15 11:14:25

标签: algorithm dynamic-programming edit-distance

I have two strings, say str1 and str2. I need to convert the first one to the second one while making the least number of edits. This is what is called as Edit Distance. Suppose we need to convert Sunday to Saturday. The first letter is the same, and the last three are the same as well, so it boils down to converting un to atur. This can be done in 3 steps - Replace 'n' with 'r', insert 't', insert 'a'. That gives the edit distance as 3. Following is the program to find out the edit distance -

// A Dynamic Programming based C++ program to find minimum
// number operations to convert str1 to str2
#include<bits/stdc++.h>
using namespace std;

// Utility function to find minimum of three numbers
int min(int x, int y, int z) 
{
    return min(min(x, y), z);
}

int editDistDP(string str1, string str2, int m, int n)
{
    // Create a table to store results of subproblems
    int dp[m+1][n+1];

    // Fill d[][] in bottom up manner
    for (int i=0; i<=m; i++)
    {
        for (int j=0; j<=n; j++)
        {
            // If first string is empty, only option is to
            // isnert all characters of second string
            if (i==0)
                dp[i][j] = j;  // Min. operations = j

            // If second string is empty, only option is to
            // remove all characters of second string
            else if (j==0)
                dp[i][j] = i; // Min. operations = i

            // If last characters are same, ignore last char
            // and recur for remaining string
            else if (str1[i-1] == str2[j-1])
                dp[i][j] = dp[i-1][j-1];

            // If last character are different, consider all
            // possibilities and find minimum
            else
                dp[i][j] = 1 + min(dp[i][j-1],  // Insert
                                   dp[i-1][j],  // Remove
                                   dp[i-1][j-1]); // Replace
        }
    }

    return dp[m][n];
}

// Driver program
int main()
{
    // your code goes here
    string str1 = "sunday";
    string str2 = "saturday";

    cout << editDistDP(str1, str2, str1.length(), str2.length());

    return 0;
}

While this returns the correct result, I also need to output the exact steps of conversion, i.e. something like

Sunday -> Surday -> Sturday -> Saturday.

How do I do the second step?

1 个答案:

答案 0 :(得分:2)

创建dp表格后,您可以按照创建表格的方式,将(m, n)改为(0, 0)

这是一个打印修改的解决方案,但您也可以返回修改矢量。

int editDistDP(string str1, string str2)
{
    int m = str1.length();
    int n = str2.length();
    int dp[m + 1][n + 1];
    int i, j;

    for (i = 0; i <= m; i++) {
        for (j = 0; j <= n; j++) {
            if (i == 0) {
                dp[i][j] = j;
            } else if (j == 0) {
                dp[i][j] = i;
            } else if (str1[i-1] == str2[j-1]) {
                dp[i][j] = dp[i-1][j-1];
            } else {            
                dp[i][j] = 1 + min3(dp[i][j - 1],
                                    dp[i - 1][j],
                                    dp[i - 1][j - 1]);
            }
        }
    }

    i = m; j = n;

    while (i && j) {
        if (i == 0) {
            cout << "insert " << str2[j - 1] << endl;
            j--;
        } else if (j == 0) {
            cout << "remove " << str1[i - 1] << endl;
            i--;
        } else if (str1[i - 1] == str2[j - 1]) {
            i--; j--;
        } else {        
            int k = imin3(dp[i][j - 1],
                          dp[i - 1][j],
                          dp[i - 1][j - 1]);

            if (k == 2) {
                cout << "replace " << str1[i - 1] 
                     << " with " << str2[j - 1] << endl;
                i--; j--;
            } else if  (k == 1) {
                cout << "remove " << str1[i - 1] << endl;
                i--;

            } else {
                cout << "insert " << str2[j - 1] << endl;
                j--;
            }
        }
    }

    return dp[m][n];
}

这里,imin3是一个函数,它返回列表中最小元素的索引0,1或2。