看到2叉数,想到两组算法:DFS和分治。本题使用分治,答案来自大神basketwang的YouTube解答(https://www.youtube.com/watch?v=Lq3Kr7-qXGI)。希望有一天自己也能独立想出来。
废话不多说,思路是这样: 若S1和S2互为scramble string <=> 存在下标idx,使得下图的两种情况之一成立。
为了证明上述命题成立。先定义"a ~ b"表示a与b互为scrabled string,a可以通过一些旋转变成b(通过二叉树的旋转)。
<=, 右推左):
其实等价于(a1 ~ b1且a2 ~ b2) 或者 (a1 ~ b2且a2 ~ b1) => a1+a2 ~ b1+b2
Case I: 若a1 ~ b1且a2 ~ b2,那么对于a1+a2 -> 把整个字符分成a1 和a2 -> 先将a1 变成b1,再将a2 变成b2 -> 连接a1和a2 变换后的string -> b1+b2
Case II: 若a1 ~ b2且a2 ~ b1,那么对于a1+a2 -> 把整个字符分成a1 和a2 -> 先将a1 变成b2,再将a2 变成b1 -> 对换a1和a2 变换后的string再连接 -> b1+b2
=>,左推右):
反证法: 若S1 ~ S2, 假设不存在分割idx使得Case I或Case II成立,=> 对于任意idx,Case I和Case II都不成立 => 对于所有idx,(S1的前idx个字符不能变换得到S2的前idx个字符,或者S1的后n-idx个字符既不能变换得到S2的后n-idx个字符)而且(S1的前idx个字符不能变换得到S2的后idx个字符,或者S1的后n-idx个字符既不能变换得到S2的前n-idx个字符)。说明S1不能拆分成左右子树,再由左右子树变换之后,连接生成S2,这与S1 ~ S2矛盾。(这个证明好像哪里有点问题,如有错误,欢迎指正)。
这样一来,只要通过分解+递归记得求解,代码如下:
class Solution(object): def wordCounts(self,s): counts={} for c in s: counts[c]=0 for c in s: counts[c]+=1 return(counts) def isScramble(self, s1, s2): """ :type s1: str :type s2: str :rtype: bool """ if s1==s2: return(True) n=len(s1) counts1=self.wordCounts(s1) counts2=self.wordCounts(s2) if counts1!=counts2: return(False) for idx in range(1,n): s1left,s1right=s1[0:idx],s1[idx:] if self.isScramble(s1left,s2[0:idx]) and self.isScramble(s1right,s2[idx:]): return(True) if self.isScramble(s1left,s2[(n-idx):]) and self.isScramble(s1right,s2[0:(n-idx)]): return(True) return(False)