[LeetCode] Scramble String 字符串 dp

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.

Hide Tags
 Dynamic Programming String
 
    题目开始想还是挺复杂的,第一想法便是二叉树搜索,把全部可能的结果搜出来,然后如果找到了便是,找不到便不是,这样写的话速度需要考虑,提高的方法是深度查找时候判断输入的参数中字符种类个数是否一样:
class Solution {
public:
    bool isScramble(string s1, string s2) {
        int len1 = s1.size(),len2 = s2.size();
        if(help_f(s1,s2)){
            if(s1==s2)  return true;
            for( int i =1;i<len1;i++){
                if(s1.substr(0,i)+s1.substr(i)==s2)    return true;
            }
            for( int i=1;i<len1;i++){
                if(isScramble(s1.substr(0,i),s2.substr(0,i))&&isScramble(s1.substr(i),s2.substr(i)))
                    return true;
    //            cout<<s1.substr(0,i)<<" "<<s2.substr(len2-i)<<" "<<s1.substr(len1-i)<<" "<<s2.substr(0,i)<<endl;
                if(isScramble(s1.substr(0,i),s2.substr(len2-i))&&isScramble(s1.substr(i),s2.substr(0,len2-i)))
                    return true;
            }
        }
        return false;
    }
    bool help_f(string &s1,string &s2)
    {
        if(s1.size()!=s2.size())    return false;
        int c[26]={0};
        for(int i=0;i<s1.size();i++)    c[s1[i]-'a'] ++;
        for(int i=0;i<s2.size();i++){
            c[s2[i]-'a']--;
            if(c[s2[i]-'a']<0)  return false;
        }
        return true;
    }
};
  第二想法便是动态规划了,设table[i][j][len],i j 为字符串s1 s2 的起始位置,len 为需要考虑的长度,如果s1 的i to i + len  与 s2 的 j to j+len 符合,便为true,在长度范围内,遍历每个断开的位置,有:
 
tab[i][j][len]  |=   tab[i][j][l] && tab[i+l][j+l][len-l]   or    tab[i][j][len]   |=  tab[i][j+len-l][l] && tab[i+l][j][len-l]
 
class Solution
{
public:
    bool isScramble(string s1, string s2)
    {
        int len1=s1.size(),len2=s2.size();
        if(len1!=len2)  return false;
        bool table[100][100][100]={false};
        for(int i=len1-1;i>=0;i--){
            for(int j=len1-1;j>=0;j--){
                table[i][j][1]=(s1[i]==s2[j]);
                for(int tmpLen=2;i+tmpLen<=len1&&j+tmpLen<=len1;tmpLen++){
                    for(int idx=1;idx<tmpLen;idx++){
                        table[i][j][tmpLen]|=table[i][j][idx]&&table[i+idx][j+idx][tmpLen-idx];
                        table[i][j][tmpLen]|=table[i][j+tmpLen-idx][idx]&&table[i+idx][j][tmpLen-idx];
                    }
                }
            }
        }
        return table[0][0][len1];
    }
};
 
原文地址:https://www.cnblogs.com/Azhu/p/4239980.html