Dynamic programming problems solution to interleaving strings

你。 提交于 2021-02-20 18:52:08

问题


I was trying to solve this problem, and I gave up, and found the solution below, although I do not understand how the solution works, or why it works. Any in-depth solution would be deeply appreciated.

Question:

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

For example, Given:

s1 = "aabcc"
s2 = "dbbca"
  • When s3 = "aadbbcbcac", return true.
  • When s3 = "aadbbbaccc", return false.

Solution:

  public static boolean isInterleave(String s1, String s2, String s3) {
        if (s3.length() == 0 && s1.length() == 0 && s2.length() == 0)
            return true;

        else if (s3.length() != s1.length() + s2.length())
            return false;
        boolean isInter[][] = new boolean[s1.length()+1][s2.length()+1];
        isInter[0][0] = true;
        for ( int i = 1; i <= s1.length(); ++i){
            if (s1.charAt(i-1) == s3.charAt(i-1))
                isInter[i][0] = true;
            else
                break;
        }
        for ( int i = 1; i <= s2.length(); ++i){
            if (s2.charAt(i-1) == s3.charAt(i-1))
                isInter[0][i] = true;
            else
                break;
        }
        // DP
        for ( int i = 1; i <= s1.length(); ++i){
            for ( int j = 1; j <= s2.length(); ++j){
                if (s3.charAt(i+j-1) == s1.charAt(i-1))
                    isInter[i][j] = isInter[i-1][j] || isInter[i][j];
                if (s3.charAt(i+j-1) == s2.charAt(j-1))
                    isInter[i][j] = isInter[i][j-1] || isInter[i][j];
            }
        }
        return isInter[s1.length()][s2.length()];
    }

回答1:


I'm using Python slice syntax here because it is nice. S[:-1] means the string S with its last character removed and S[:n] means the prefix of S that has length n.

The key idea is that if C is an interleaving of A and B, then C[:-1] is either an interleaving of A and B[:-1] or of A[:-1] and B. On the other hand, if C is an interleaving of A and B, then C + 'X' is an interleaving of A + 'X' and B and it is also an interleaving of A and B + 'X'.

These are the substructure properties we need to apply dynamic programming.

We define f(i, j) = true, if s1[:i] and s2[:j] can be interleaved to form s3[:(i+j)] and f(i,j) = false otherwise. By the observation above we have

f(0,0) = true
f(i,0) = f(i-1, 0) if s3[i-1] == s1[i-1]
f(0,j) = f(0, j-1) if s3[j-1] == s2[j-1]
f(i,j) = true if s3[i+j-1] = s1[i-1] and f(i-1, j)
f(i,j) = true if s3[i+j-1] = s2[j-1] and f(i, j-1)

In all the other cases we have f(i,j) = false. The Java code just implements this recurrence using dynamic programming. That said, I would implement it in a bit more concise way:

for (int i = 0; i <= s1.length(); ++i)
    for (int j = 0; j <= s2.length(); ++j)
        isInter[i][j] = (i == 0 && j == 0)
           || (i > 0 && s1.charAt(i-1) == s3.charAt(i+j-1) && isInter[i-1][j])
           || (j > 0 && s2.charAt(j-1) == s3.charAt(i+j-1) && isInter[i][j-1]);



回答2:


The first few lines just deal with simple cases that can be resolved based only on the input string lengths. These tests simplify the remaining code by allowing it to assume that the lengths match.

The guts of the algorithm calculate an array isInter, where isInter[i][j] is true after iteration (i,j) if, and only if, the first i+j characters of s3 can be formed by interleaving the first i characters of s1 with the first j characters of s2.

isInter[i][0] is true if, and only if, the first i characters of s3 match the first i characters of s1. Similarly, isInter[0][i] is true if, and only if, the first i characters of s3 match the first i characters of s2.

The final loop builds up the remaining elements of isInter using already calculated elements and matches between the next character of s3 and either the next character of s1 or the next character of s2.

After isInter has been completely calculated, isInter[s1.length()][s2.length()] is true if, and only if, the whole of s3 can be formed by interleaving the whole of s1 with the whole of s2.




回答3:


Here is another attempt to show how the code works, using extremely plain syntax in C++. Their are some inline comments in the code for you to understand. It can't get simpler than this :)

//using dynamic programming : O(n^2)
bool is_interleaved_On2_DP(string s1, string s2, string s3)
    {
    bool ret = false;
    int len1 = s1.length();
    int len2 = s2.length();
    int len3 = s3.length();

    if( len1 + len2 != len3 )
        {
        return ret;
        }

#define M(i, j) match[ (i) * len1 + (j) ]

    //bool match[len1 + 1][len2 + 1]; //todo; use dynamic allocation
    bool* match = new bool[ (len1+1)*(len2+1) ];
    int i, j, k;

    /* init match table to be all false */
    for( i = 0; i <= len1; i++ )
        {
        for( j = 0; j <= len2; j++ )
            {
            M(i, j) = false;
            }
        }

    /* init match[0][0] == true */
    M(0, 0) = true; //why ? null is interleaving 2 other nulls :)

    /* init the s1 side of table i.e. column */
    for( i = 1; i <= len1; i++ )
        {
        char c1 = s1[i - 1];
        char c3 = s3[i - 1];
        if(c1 == c3)
            {
            M(i, 0) = true;
            }
        else
            {
            break;
            }
        }

    /* init the s2 side of table i.e. row */
    for( j = 1; j <= len2; j++ )
        {
        char c2 = s2[j - 1];
        char c3 = s3[j - 1];
        if(c2 == c3)
            {
            M(0, j) = true;
            }
        else
            {
            break;
            }
        }

    /* compute remaining table */
    for( i = 1; i <= len1; i++ )
        {
        char c1 = s1[i - 1];
        for( j = 1; j <= len2; j++ )
            {
            char c2 = s2[j - 1];
            int k = i + j; //index for s3
            char c3 = s3[k - 1];

            if(c1 == c3)
                {
                M(i, j) = M(i - 1, j) || M(i, j);
                }

            if(c2 == c3)
                {
                M(i, j) = M(i, j - 1) || M(i, j);
                }
            }
        }

    ret = M(len1, len2);

    delete [] match;
#undef M
    return ret;
    }


来源:https://stackoverflow.com/questions/22795589/dynamic-programming-problems-solution-to-interleaving-strings

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!