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.
思路:对付复杂问题的方法是从简单的特例来思考。简单情况:
- 如果字符串长度为1,那么必须两个字符串完全相同;
- 如果字符串长度为2,例如s1='ab',则s2='ab'或s2='ba'才行
- 如果字符串任意长度,那么可以把s1分为a1, b1两部分,s2分为a2,b2两部分。需要满足:((a1=a2)&&(b1=b2)) || ((a1=b2)&&(a2=b1)) =>可用递归
class Solution { public: bool isScramble(string s1, string s2) { if(s1 == s2) return true; for(int isep = 1; isep < s1.size(); ++ isep) { //traverse split pos string seg11 = s1.substr(0,isep); string seg12 = s1.substr(isep); //see if a1=a2 &&b1=b2 is ok string seg21 = s2.substr(0,isep); string seg22 = s2.substr(isep); if(isScramble(seg11,seg21) && isScramble(seg12,seg22)) return true; //see if a1=b2 &&a2=b1 is ok seg21 = s2.substr(s2.size() - isep); //从后截取isep长度 seg22 = s2.substr(0,s2.size() - isep); if(isScramble(seg11,seg21) && isScramble(seg12,seg22)) return true; } return false; } };
Result: Time Limit Exceeded
思路II: 动态规划。三维状态dp[i][j][k],前两维分别表示s1和s2的下标起始位置,k表示子串的长度。dp[i][j][k]=true表示s1(i, i+k-1)和s2(j, j+k-1)是scramble。
状态转移方程:if(dp[i][j][split] && dp[i+split][j+split][k-split] || dp[i][j+k-split][split] && dp[i+split][j][k-split]) dp[i][j][k]=true;
因为在状态转移方程中k又要分割成更小的值,所以必须已知小值,k从小到大遍历。
class Solution { public: bool isScramble(string s1, string s2) { int len = s1.length(); if(len==0) return true; if(s1 == s2) return true; //初始状态 vector<vector<vector<bool>>> dp(len, vector<vector<bool>>(len, vector<bool>(len+1, false) ) ); for (int i = 0; i < len; ++i) { for (int j = 0; j < len; ++j) { dp[i][j][1] = s1[i]==s2[j]; } } //状态转移 for(int k = 2; k <= len; k++) //从较短的子串开始分析,为了状态转方程 { for(int s1Pointer = 0; s1Pointer+k-1 < len; s1Pointer++) { for(int s2Pointer = 0; s2Pointer+k-1 < len; s2Pointer++) { for(int split = 1; split < k; split++) //levelSize长度的任意一种分割 { if ((dp[s1Pointer][s2Pointer][split] && dp[s1Pointer+split][s2Pointer+split][k-split]) || (dp[s1Pointer][s2Pointer+k-split][split] && dp[s1Pointer+split][s2Pointer][k-split])) { dp[s1Pointer][s2Pointer][k] = true; break; }; } } } } return dp[0][0][len]; } };