题目描述:
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":
1 2 3 4 5 6 7 8
   |     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".
1 2 3 4 5 6 7 8
   |     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".
1 2 3 4 5 6 7 8
   |     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.
看完这道题, 首先想到的是使用递归, 但是思维惯性让我觉得递归可能超时, 所以按照tag中的动态规划方法来做, 我是使用了三维数组来进行动态规划, 有四重循环, 所以可能还有优化空间. dp[i][j][k]表示s1[i]和s2[j]开始的长度为k的子串是不是scramble的, 最后要返回的结果是dp[0][0][s1.length()], 所以i和j要从大到小遍历.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | class Solution { public:     bool isScramble(string s1, string s2) {         if(s1.length() != s2.length()) return false;         int len = s1.length();         vector<vector<vector<int>>> dp(len, vector<vector<int>>(len, vector<int>(len + 1, 0)));                  for(int i = 0; i < len; i++){             for(int j = 0; j < len; j++){                 if(s1[i] == s2[j]){                     dp[i][j][1] = 1;                 }             }         }                  for(int i = len - 1; i >= 0; i--){             for(int j = len - 1; j >= 0; j--){                 for(int k = 2; i + k <= len && j + k <= len; k++){                     for(int r = 1; r < k && !dp[i][j][k]; r++){                         dp[i][j][k] = (dp[i][j][r] && dp[i + r][j + r][k - r]) || (dp[i][j + k - r][r] && dp[i + r][j][k - r]);                     }                 }             }         }
          return dp[0][0][len];     } };
  | 
 
但是这个方法速度并不是很理想, 比较快的方法反而是递归+剪枝, 在递归前先判断字符串中字母数量是不是相同, 如果不相同则可以直接返回false.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | class Solution { public:     bool isScramble(string s1, string s2) {         if(s1.length() != s2.length()) return false;         return isScrambleImpl(s1, s2, 0, 0, s1.length());     }          bool isScrambleImpl(string &s1, string &s2, int start1, int start2, int len){         vector<int> charTimes(26, 0);         for(int i = start1; i < start1 + len; i++){             charTimes[s1[i] - 'a']++;         }         int flag  = true;         for(int i = start2; i < start2 + len; i++){             charTimes[s2[i] - 'a']--;             if(charTimes[s2[i] - 'a'] < 0){                 flag = false;                 break;             }         }         if(!flag) return false;         if(len == 1 && len == 1) return true;          for(int i = 1; i < len; i++){             if((isScrambleImpl(s1, s2, start1, start2, i) && isScrambleImpl(s1, s2, start1 + i, start2 + i, len - i))                 || (isScrambleImpl(s1, s2, start1, start2 + len - i, i) && isScrambleImpl(s1, s2, start1 + i, start2, len - i))){                     return true;                 }         }         return false;     } };
  |