原题:
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”.
(原题太长了我就不复制了,详细见 https://leetcode.com/problems/scramble-string/description/)
大致题意:
对于任何一个字符串s1,我们可以把它递归地看成一颗二叉树从而分为两段非空的子串。去“翻滚”(有的地方也翻译为爬升,有点不能理解)s1,我们可以选择任何一个非叶子节点,然后交换其两个儿子节点。其中要注意的是,可以选择多个子节点进行多次交换。
这个题目可以用递归或者动态规划进行求解。动态规划暴力求解比较好理解,写一个isScramble函数:如果两个字符串相等,则毫无疑问返回true。否则遍历一次s1的长度去分别划分s1和s2为两个子串,并递归地判断isScramble(s1左,s2左) && isScramble(s1右,s2右)或者isScramble(s1右,s2左) && isScramble(s1左,s2右)。
有个小技巧就是一开始sort一下然后判断是否相同,至少可以看出两个字符串是否是anagram,否则程序也没必要继续执行。
class Solution {
public:
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size()) return false;
if (s1 == s2) return true;
string t1 = s1, t2 = s2;
sort(t1.begin(), t1.end());
sort(t2.begin(), t2.end());
if (t1 != t2) return false;
for (int len = 1; len < s1.size(); len++) {
string l1 = s1.substr(0, len), l2 = s2.substr(0, len);
string r1 = s1.substr(len), r2 = s2.substr(len);
if (isScramble(l1, l2) && isScramble(r1, r2)) return true;
l2 = s2.substr(0, s1.size() - len);
r2 = s2.substr(s1.size() - len);
if (isScramble(l1, r2) && isScramble(r1, l2)) return true;
}
return false;
}
};
缺点是调用了很多次substr(),不过最后跑出来也是beat了70%。。我还写过一个递归版本,可能哪里写的有问题,跑出来时间还不如这个版本快