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.我的解答 好不容易寫成功的哇哇~~ 最後還是超時了。。。。淚崩~~~
要對s1進行改變,然後判斷s2是否存在於s1的變換集合中
我的想法就是,對字符串進行依次個切分,然後把兩部分進行遞歸交換,把交換的都存在集合裏,最後組合起來看看是不是跟s2是否相等。
比如 abcd 依次劃分爲a,bcd ab,cd abc,d
然後依次對各個部分遞歸
用dfs?? 同時記下來每個狀態的變換,用記憶化搜索方法
class Solution {
public:
void solve(string s, map<string,set<string>>& sets){
map<string,set<string>> s1, s2;
if(s.size() == 1){
if(sets.find(s) == sets.end())
sets[s].insert(s);
return;
}
if(sets.find(s) != sets.end())
return;
else
sets[s].insert(s); //這裏注意下,要把s本身也加入進去
for(int i = 0; i < s.size()-1; i++){
string p1 = s.substr(0,i+1);
string p2 = s.substr(i+1);
solve(p1,s1);
solve(p2,s2);
for(set<string>::iterator it = s1[p1].begin(); it != s1[p1].end(); it++){
for(set<string>::iterator is = s2[p2].begin(); is != s2[p2].end(); is++){
string t = *it + *is; //這裏也要注意下,交換和不交換都要記錄進去 如 a+f(bc)
sets[s].insert(t);
t = *is + *it; // f(bc)+a
sets[s].insert(t);
}
}
}
}
bool isScramble(string s1, string s2) {
if(s1.size() != s2.size() || s1.size() == 0 || s2.size() == 0) return false;
if(s1.size() == 1){
if(s1[0] == s2[0])
return true;
else
return false;
}
map<string,set<string>> sets;
solve(s1, sets);
for(set<string>::iterator it = sets[s1].begin(); it != sets[s1].end(); it++){
if(*it == s2)
return true;
}
return false;
}
};
2. 用動態規劃的方法
大神真是天才啊啊啊
解題思路: 因爲這道題根本就是對s1進行中間某段的切分,因此只要從1~n-1的切分點進行遍歷,然後比較s1是前i個部分和s2的前i個部分(當然還有對應的後n-i個的部分),這種情況下的對應上呢?
還是s2的後i個部分和s1的前i個部分對應上呢? 這種情況就是對s1的第i個點進行旋轉了。
同時在比較以上步驟之前,先判斷s1 s2兩部分是否字母都相同,如果不同就直接返回false
注意點: 這裏我漏了一個,就是如果s1==s2,直接就return true; 無需再進行比較;這也避免了出現空串和單個字母的情況的出現的處理了、
以下是代碼:
class Solution {
public:
bool equals(string s1, string s2){//判斷s1和s2中的字母是否都相同,這是最基本的判斷
int c[26];
memset(c, 0, sizeof(c));
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;
}
bool isScramble(string s1, string s2) {
if(s1.size() != s2.size()) return false;
int n = s1.size();
if(s1 == s2) return true;
if(equals(s1, s2)){
for(int i = 1; i < s1.size(); i++){ //這個是個數
string s11 = s1.substr(0,i); //s1的前i個數
string s12 = s1.substr(i); //s1的後n-i個數
string s21 = s2.substr(0,i); //s2的前i個數
string s22 = s2.substr(i); //s2的後n-i個數
string s23 = s2.substr(n-i); //s2的後i個數
string s24 = s2.substr(0,n-i); //s2的後n-i個數
if(isScramble(s11,s21) && isScramble(s12,s22))
//假如是對s1沒有旋轉,就把s1,s2 對應的第i部分切開的前i個和後n-i個進行比較
return true;
if(isScramble(s11, s23) && isScramble(s12, s24)) //假如對s1進行旋轉,就把s1的前i個和s2的後i個進行比較
return true;
}
}
return false;
}
};