题目链接: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.

这道题的要求是判断两个字符串是否是Scramble String。

如果两个字符串是Scramble String,则其长度必然相等。而且,在某位置切开s1,则s1左侧与s2左侧相同数量的子串为Scramble String,并且s1右侧与s2右侧相同数量的子串为Scramble String;或者s1左侧与s2右侧相同数量的子串为Scramble String,并且s1右侧与s2左侧相同数量的子串为Scramble String。

1. 递归处理

思路有了,就可以通过递归调用遍历每组分割点了。其中a1和b1分别表示s1中以a1开始b1结束的子串,a2和b2分别表示s2中以a2开始b2结束的子串。

 1 bool isScramble(string s1, int a1, int b1, string s2, int a2, int b2)
 2 {
 3     if(b1 - a1 != b2 - a2)
 4         return false;
 5     if(a1 == b1)
 6         return s1[a1] == s2[a2];
 7     
 8     for(int i = a1; i < b1; ++ i)
 9     {
10         if(isScramble(s1, a1, i, s2, a2, a2 + i - a1) && 
11            isScramble(s1, i + 1, b1, s2, b2 - (b1 - i - 1), b2))
12             return true;
13         if(isScramble(s1, a1, i, s2, b2 - (i - a1), b2) && 
14            isScramble(s1, i + 1, b1, s2, a2, a2 + b1 - i - 1))
15             return true;
16     }
17     
18     return false;
19 }

遗憾的是,超时。。。仔细想一下,还可以进行剪枝:如果s1和s2的子串中的字符不相同,则其必然不是Scramble String。

顺利AC。

时间复杂度:O(???)

空间复杂度:O(1)

 1 class Solution
 2 {
 3 public:
 4     bool isScramble(string s1, string s2)
 5     {
 6         return isScramble(s1, 0, s1.size() - 1, s2, 0, s2.size() - 1);
 7     }
 8 private:
 9     bool isScramble(string s1, int a1, int b1, string s2, int a2, int b2)
10     {
11         if(b1 - a1 != b2 - a2)
12             return false;
13         if(a1 == b1)
14             return s1[a1] == s2[a2];
15         
16         // 剪枝,如果子串中的字符不同,则必然不是Scramble String,不用再进行分割处理了
17         int cnt[256] = {0};
18         for(int i = a1; i <= b1; ++ i)
19             ++ cnt[s1[i]];
20         for(int i = a2; i <= b2; ++ i)
21             -- cnt[s2[i]];
22         for(int i = 0; i < 256 ;++ i)
23             if(cnt[i] != 0)
24                 return false;
25         
26         for(int i = a1; i < b1; ++ i)
27         {
28             if(isScramble(s1, a1, i, s2, a2, a2 + i - a1) && 
29                isScramble(s1, i + 1, b1, s2, b2 - (b1 - i - 1), b2))
30                 return true;
31             if(isScramble(s1, a1, i, s2, b2 - (i - a1), b2) && 
32                isScramble(s1, i + 1, b1, s2, a2, a2 + b1 - i - 1))
33                 return true;
34         }
35         
36         return false;
37     }
38 };

2. 动态规划

维护变量dp[i][j][len],其中i是s1的起始字符,j是s2的起始字符,而n是当前的字符串长度,表示的是以i和j分别为s1和s2起点的长度为len的字符串是不是互为Scramble String。

递推公式也是前面的思路:dp[i][j][len] ||= (dp[i][j][k]&&dp[i+k][j+k][len-k] || dp[i][j+len-k][k]&&dp[i+k][j][len-k])。

参考自这里

时间复杂度:O(???)

空间复杂度:O(1)

 1 class Solution
 2 {
 3 public:
 4     bool isScramble(string s1, string s2)
 5     {
 6         if(s1.size() == 0)
 7             return true;
 8         // dp[i][j][len]表示的是以i和j分别为s1和s2起点的长度为len的字符串是不是互为Scramble String
 9         vector<vector<vector<bool> > > dp(s1.size(), 
10             vector<vector<bool> >(s2.size(), 
11             vector<bool>(s1.size() + 1, false)));
12         for(int i = 0; i < s1.size(); ++ i)
13             for(int j = 0; j < s2.size(); ++ j)
14                 dp[i][j][1] = s1[i] == s2[j];
15         
16         for(int len = 2; len <= s1.size(); ++ len)
17             for(int i = 0; i < s1.size() - len + 1; ++ i)
18                 for(int j = 0; j < s2.size() - len + 1; ++ j)
19                     for(int k = 1; k < len; ++ k)
20                         dp[i][j][len] = dp[i][j][len] || 
21                                         dp[i][j][k] && dp[i + k][j + k][len - k] || 
22                                         dp[i][j + len - k][k] && dp[i + k][j][len - k];
23         
24         return dp[0][0][s1.size()];
25     }
26 };