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.
挺难的一道题,刚开始做的时候以为建树的规则是二分,结果才发现是随机的划分建树。
应该如何做呢?
我们先来看简单的情况,如果说划分是确定的,是每次都平均分成两份,如果字符数是单数则前半份比后半份少一。
比如题目中的“great”就是极好的例子。
由于已知划分点,我们可以知道原来字符串的建树:
假设需要检查的字符串是X1X2X3X4X5,那么,由于知道是对半划分,可知:
①要么:gr对应X1X2,同时eat对应X3X4X5;
②要么:gr对应X4X5,同时eat对应X1X2X3;比如此时X1X2X3X4X5为eatgr。
对于gr,同理:
如果是①,那么将gr对半划分,可知:
①①要么:g对应X1,同时r对应X2;
①②要么:r对应X1,同时g对应X2;比如:rgeat。
剩下步骤同理。
综上,如果可知建树的规则是对半平分,那么我们只需深搜一下,对两个字符串不断地平分,匹配,直到发现匹配或者深搜完了都没有匹配。
但是,这里的规则并不是平分。
那么只需要在深搜中将当前字符串依次划分就好了,比如先划成X1, X2X3X4X5试试,然后是X1X2, X3X4X5,接着X1X2X3, X4X5……
对于每一次深搜,如果当前两个划分的字符串(各来自题目给的两个string)刚好相等,说明当前划分是匹配的,返回true(但是还没有匹配完,还有两个string剩下的部分);
如果当前的两个字符串无法一一对应(也就是分别排序后还不相等),那么当前划分不匹配。
class Solution {
public:
int * letters;
string S1, S2;
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size()) return false;
letters = new int[60];
S1 = s1, S2 = s2;
return dfs(0, S1.size(), 0, S2.size());
}
bool dfs(int l1, int r1, int l2, int r2) { // 这里用四个下标来指代当前两个字符串
if (S1.substr(l1, r1 - l1) == S2.substr(l2, r2 - l2)) return true; // 如果当前两个字符串相等了
for (int i = 0; i < 52; i++) letters[i] = 0; // 检查两个当前字符串的字母类型和个数是否一样
for (int i = l1; i < r1; i++)
if ('A' <= S1[i] && S1[i] <= 'Z') letters[S1[i] - 'A']++;
else letters[S1[i] - 71]++;
for (int i = l2; i < r2; i++)
if ('A' <= S2[i] && S2[i] <= 'Z') letters[S2[i] - 'A']--;
else letters[S2[i] - 71]--;
for (int i = 0; i < 52; i++) if (letters[i]) return false;
for (int i = 1; i < r1 - l1; i++) {
if ((dfs(l1, l1 + i, l2, l2 + i) && dfs(l1 + i, r1, l2 + i, r2))) return true; // 如果gr和X1X2匹配且eat和X3X4X5匹配
if ((dfs(l1, l1 + i, r2 - i, r2) && dfs(l1 + i, r1, l2, r2 - i))) return true; // 如果gr和X4X5匹配且eat和X1X2X3匹配
}
return false;
}
};