您的位置:首页 > 其它

87. Scramble String

2016-09-02 20:55 253 查看
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;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dynamic programming