LeetCode | Scramble String(字符交换)


Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.

Below is one possible representation of s1 = "great":

    great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t

To scramble the string, we may choose any non-leaf node and swap its two children.

For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat".

    rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t

We say that "rgeat" is a scrambled string of "great".

Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae".

    rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a

We say that "rgtae" is a scrambled string of "great".

Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.

题目解析:

凡是树的问题,就自然想到了递归算法。不过自己想的算法跟“判断前序遍历和后序遍历是否为同一个树”的方法一样。但导致了问题:

错误代码:

class Solution {
public:
    bool isScramble(string s1, string s2) {
        if(s1.size() != s2.size())
            return false;
        return JudgeScramble(s1,0,s1.size()-1,s2,0,s2.size());

    }
    bool JudgeScramble(string s1,int begin1,int end1,string s2,int begin2,int end2){
        if(begin1 > end1)
            return true;
        int i = begin2;
        while(i <= end2){
            if(s1[begin1] == s2[i])
                break;
            i++;
        }
        if(i > end2)
            return false;
        int len = i-begin2;
        return JudgeScramble(s1,begin1+1,begin1+len,s2,begin2,i-1) && JudgeScramble(s1,begin1+len+1,end1,s2,i+1,end2);
    }
};

出错案例

《LeetCode | Scramble String(字符交换)》

然后就没有想到更合适的方法,一直在树的范围内挣扎。上网看了别人的方案后才知道,是按照字符串的形式来处理的。而对于分割点则采用枚举的方法……就是把s1分为两个串a1,a2;s2分为两个串b1,b2,只要长度相同而且能对应上(就是可以通过交换得来)就可以了,然后递归判断每个子串。下面是递归的方案:

bool isScramble(string s1, string s2) {  
    int lens1,lens2;  
    lens1 = s1.length();  
    lens2 = s2.length();  
    if(lens1!=lens2)  
        return false;  
    if(lens1==0)  
        return true;  
    if (lens1==1)  
    {  
        return s1[0]==s2[0];  
    }  
    if (lens2==2)  
    {  
        return (s1[0]==s2[0]&&s1[1]==s2[1])||(s1[0]==s2[1]&&s1[1]==s2[0]);  
    }  
    string stra1,stra2,strb1,strb2;  
    for(int i=1;i<lens1;i++)  
    {  
        stra1 = s1.substr(0,i);  
        stra2 = s1.substr(i,lens1-i);  
        strb1 = s2.substr(0,i);  
        strb2 = s2.substr(i,lens2-i);  
        if (isScramble(stra1,strb1)&&isScramble(stra2,strb2))  
        {  
            return true;  
        }  
        stra1 = s1.substr(0,lens1-i);  
        stra2 = s1.substr(lens1-i,i);  
        if (isScramble(stra1,strb2)&&isScramble(stra2,strb1))  
        {  
            return true;  
        }  
    }  
    return false;  
}  

由于判断子串的时候,很多重复,就用动态规划来优化,如何优化呢?这也是一个很棘手的问题。

dp[i][j][k] 代表了s1从i开始,s2从j开始,长度为k的两个substring是否为scramble
string。
有三种情况需要考虑:

1. 如果两个substring相等的话,则为true

2. 如果两个substring中间某一个点,左边的substrings为scramble string,同时右边的substrings也为scramble string,则为true

3. 如果两个substring中间某一个点,s1左边的substring和s2右边的substring为scramble
string, 同时s1右边substring和s2左边的substring也为scramble string,则为true


class Solution {
public:
    bool isScramble(string s1, string s2) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        if (s1.length() != s2.length()) {
            return false;
        }
        int length = s1.length();
        bool f[length][length][length];
        memset(f, false, sizeof(bool) * length * length * length);
        
        for (int k = 1; k <= length; k++) {
            for (int i = 0; i <= length - k; i++) {
                for (int j = 0; j <= length - k; j++) {
                    if (k == 1) {
                        f[i][j][k] = s1[i] == s2[j];
                    }
                    else {
                        for (int l = 1; l < k; l++) {
                            if ((f[i][j][l] && f[i + l][j + l][k - l]) || (f[i][j + k - l][l] && f[i + l][j][k - l])) {
                                f[i][j][k] = true;
                                break;
                            }                            
                        }
                    }
                }
            }            
        }
                
        return f[0][0][length];
    }
};

点赞