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.
1 class Solution { 2 public: 3 bool anagram(string s1, string s2){ 4 if(s1.size() != s2.size()) return false; 5 sort(s1.begin(), s1.end()); 6 sort(s2.begin(), s2.end()); 7 return s1 == s2; 8 } 9 bool isScramble(string s1, string s2) { 10 if (s1.empty() && s2.empty()) return true; 11 if (s1.length() != s2.length()) return false; 12 if (s1 == s2) return true; 13 if (!anagram(s1, s2)) return false; 14 bool ret = false; 15 int n = s1.length(); 16 17 for (int i = 1; i < n; i++) { 18 ret = isScramble(s1.substr(0, i), s2.substr(n - i, i)) && isScramble(s1.substr(i, n - i), s2.substr(0, n - i)); 19 if (ret) return true; 20 ret = isScramble(s1.substr(0, i), s2.substr(0, i)) && isScramble(s1.substr(i, n - i), s2.substr(i, n - i)); 21 if (ret) return true; 22 } 23 return ret; 24 } 25 };
递归的算法一开始TLE,知道要试着剪枝,看了discussion之后发现可以加了anagram检测之后就AC了。。。
动态规划的算法想不出来。其实关键是把重复的子问题找出来。下午真是脑子生锈了。。。google了一下发现其实也挺简单的。。。算了,下次再做。
Method II
1 class Solution { 2 public: 3 bool isScramble(string s1, string s2) { 4 int n1 = s1.length(), n2 = s2.length(); 5 if (n1 != n2) return false; 6 if (n1 == 0) return true; 7 8 //vector<vector<vector<bool> > > dp(n1, vector<vector<bool> >(n1, vector<bool>(n1 + 1, false))); 9 //bool *** dp = new bool**[n1]; 10 bool dp[100][100][100]; 11 memset(dp, 0, 1000000*sizeof(bool)); 12 for (int i = 0; i < n1; ++i) { 13 //dp[i] = new bool*[n1]; 14 for (int j = 0; j < n2; ++j) { 15 //dp[i][j] = new bool[n1 + 1]; 16 //memset(dp[i][j], 0, sizeof(bool) * (n1 + 1)); 17 if (s1[i] == s2[j]) dp[i][j][1] = true; 18 } 19 } 20 21 22 for (int len = 2; len <= n1; ++len) { 23 for (int i = 0; i <= n1 - len; ++i) { 24 for (int j = 0; j <= n2 - len; ++j) { 25 for (int l = 1; l < len; ++l) { 26 if ((dp[i][j][l] && dp[i + l][j + l][len - l]) || (dp[i][j + len - l][l] && dp[i + l][j][len - l])) { 27 dp[i][j][len] = true; 28 break; 29 } 30 } 31 } 32 } 33 } 34 35 return dp[0][0][n1]; 36 } 37 };
如果用vector的话,accepted需要570ms;如果用数组的话就可以60msaccepted。递归其实才28ms。。。。
动态规划的时间复杂度是O(n^4)。
第三次写。
1 class Solution { 2 public: 3 bool isScramble(string s1, string s2) { 4 if (s1.length() != s2.length()) return false; 5 int n1 = s1.length(), n2 = s2.length(); 6 bool dp[100][100][100]; 7 8 for (int len = 1; len <= n2; len++) { 9 for (int i = 0; i + len <= n1; i++) { 10 for (int j = 0; j + len <= n2; j++) { 11 dp[i][j][len] = (len == 1 && s1[i] == s2[j]); 12 for (int m = 1; m < len; m++) { 13 dp[i][j][len] = (dp[i][j][m] && dp[i + m][j + m][len - m]) || (dp[i][j + len - m][m] && dp[i + m][j][len - m]); 14 if (dp[i][j][len]) break; 15 } 16 } 17 } 18 } 19 return dp[0][0][n1]; 20 } 21 };