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.

Leetcode:Scramble String  解题报告

解答:
1. Brute Force 递归。
基本的思想就是:在S1上找到一个切割点,左边长度为i, 右边长为len - i。 有2种情况表明它们是IsScramble
(1). S1的左边和S2的左边是IsScramble, S1的右边和S2的右边是IsScramble
(2). S1的左边和S2的右边是IsScramble, S1的右边和S2的左边是IsScramble (实际上是交换了S1的左右子树)

而i的取值可以是1  ~  len-1。 基于这个思想,我们可以写出以下的递归Brute Force 解:

引自stellari对复杂度的解释:

stellari

看了你的不少文章,感觉收获良多!只是有点小问题想请教:按照我的理解,那个递归算法在最差情况下应该是O(3^n),而非O(n^2)。理由是:假设函数运行时间为f(n),那么由于在每次函数调用中都要考虑1~n之间的所有长度,并且正反都要检查,所以有
f(n) = 2[f(1) + f(n-1)] +2[f(2) + f(n-2)] … + 2[f(n/2) + f(n/2+1)]. 易推得f(n+1) = 3(fn), 故f(n) = O(3^n)。当然这是最差情况下的时间复杂度。那么你提到的O(n^2),是否是通过其他数学方法得到的更tight的上限?欢迎探讨!

这一个解是不能通过LeetCode的检查的,复杂度是 3^N

 1 public static boolean isScramble1(String s1, String s2) {
 2         if (s1 == null || s2 == null) {
 3             return false;
 4         }
 5 
 6         int len1 = s1.length();
 7         int len2 = s2.length();
 8 
 9         // the two strings should be the same length.
10         if (len1 != len2) {
11             return false;
12         }
13 
14         return rec(s1, s2);
15     }
16 
17     // Solution 1: The recursion version.
18     public static boolean rec1(String s1, String s2) {
19         int len = s1.length();
20 
21         // the base case.
22         if (len == 1) {
23             return s1.equals(s2);
24         }
25 
26         // 鍒掑垎2涓瓧绗︿覆
27         for (int i = 1; i < len; i++) {
28             // we have two situation;
29             // the left-left right-right & left-right right-left
30             if (rec1(s1.substring(0, i), s2.substring(0, i))
31                     && rec1(s1.substring(i, len), s2.substring(i, len))) {
32                 return true;
33             }
34 
35             if (rec1(s1.substring(0, i), s2.substring(len - i, len))
36                     && rec1(s1.substring(i, len), s2.substring(0, len - i))) {
37                 return true;
38             }
39         }
40 
41         return false;
42     }
View Code

相关文章: