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.
思路:二叉树是可以任意生成的,长度为n的字符串可以有C(2n,n)/(n+1)种这样的二叉树(参见卡特兰数应用)。通过两个字符串反推出二叉树有难度。注意到,变形的次数不受限制,但是仅能够对调同一个结点的两个孩子。其规律是,对调完之后,不管其孩子内部是否还会对调,两个孩子子串仍然会是Anagram。
因此,从最外层开始尝试:第一层划分(也就是二叉树的第一次分叉)发生在什么位置;以及尝试:根节点的两个孩子有没有发生对调。递归着往里进行。
class Solution {
public:
bool isScramble(string s1, string s2) {
int m = s1.size();
int n = s2.size();
if(m != n)
return false;
return isValid(s1, s2);
}
bool isAnagram(string s1, string s2)
{
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
return (s1 == s2);
}
bool isValid(string s1, string s2)
{
if(s1 == s2) //一样必正确
return true;
int n = s1.size();
if(n == 1) //不可再划分
return false;
if(!isAnagram(s1, s2)) //非变形词必错误
return false;
for(int i = 0;i<n-1;i++) //尝试分叉位置
{
//左右对调型
if(isValid(s1.substr(0, i+1), s2.substr(n-i-1)))
if (isValid(s1.substr(i+1), s2.substr(0, n-i-1)))
return true;
//左右没对调型
if(isValid(s1.substr(0, i+1), s2.substr(0, i+1)))
if (isValid(s1.substr(i+1), s2.substr(i+1)))
return true;
}
return false;
}
};
PS:判断Anagram的方法有很多,这里使用的是排序法。