码迷,mamicode.com
首页 > 其他好文 > 详细

【leetcode刷题笔记】Scramble String

时间:2014-07-23 15:06:06      阅读:320      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   color   os   

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.


 

题解:

第一个想法比较naive,想把s1和s2都按照字典序排列,然后看是否相同。提交后就发现下面的例子就能够证明这个算法的错误:

s1 = "abcd"
s2 = "bdac"

第二个想法是递归,如下图所示:

bubuko.com,布布扣

对于任意长度相等的s1和s2,都可以分解成上图两种情况,通过把s1和s2分成两部分,那么有两种情况s1和s2是scramble的,一种是两部分对应scramble;一种是两部分交换后scramble。这样就有了我们的递归解法。

但是仅仅是这种递归一定会超时,必须进行优化,有一下几点可以优化的地方:

  1. s1和s2长度必须相等;
  2. 长度相等且都为0,返回true;
  3. s1和s2完全相同返回true;
  4. s1和s2所包含的字母种类个数必须相同,即s1和s2按照字典序排序后必须相同;

通过以上的优化,递归方法就不会超时了。

代码如下:

 1 public class Solution {
 2     public boolean isScramble(String s1, String s2) {
 3         int m = s1.length();
 4         int n = s2.length();
 5         
 6         if(m != n)
 7             return false;
 8         
 9         if(m == 0 || s1.equals(s2))
10             return true;
11             
12         char[] chars1 = s1.toCharArray();
13         char[] chars2 = s2.toCharArray();
14         Arrays.sort(chars1);
15         Arrays.sort(chars2);
16         for(int i = 0;i < m;i++)
17             if(chars1[i] != chars2[i])
18                 return false;
19         
20         for(int i = 1;i < m;i++){
21             String s1left = s1.substring(0,i);
22             String s1right = s1.substring(i);
23             String s2left = s2.substring(0, i);
24             String s2right = s2.substring(i);
25             
26             if(isScramble(s1left, s2left) && isScramble(s1right, s2right))
27                 return true;
28             s2left = s2.substring(0,n-i);
29             s2right = s2.substring(n-i);
30             if(isScramble(s1left, s2right) && isScramble(s1right, s2left))
31                 return true;
32         }
33         
34         return false;
35     }
36 }

上述方法耗时428ms。

第三个想法,动态规划。

递归之所以会超时,是因为做了许多重复的工作。用动态规划bottom-up的方法把这些重复的工作记录在表dp[][][]中,就可以省去重复计算的时间。

我们用dp[sublen][i][j]表示s1[i,i+sublen]和s2[j,j+sublen]是否是scramble的。那么有如下递推式:

dp[sublen][i][j] = (dp[k][i][j]&&dp[sublen-k][i+k][j+k]) || (dp[k][i][j+sublen-k] && dp[sublen-k][i+k][j]);

它对应了下图两种情况:

bubuko.com,布布扣

另外 dp[1][i][j] = s1.charAt(i) == s2.charAt(j); 

理解还算容易,写代码还是有难度的,一共四重循环:

第一重循环改变sublen的大小,从长度为2的子串一直增加至长度为n的串;

第二重循环改变i,即s1中游标的位置,从0~n-sublen;

第三重循环改变i,即s2中游标的位置,从0~n-sublen;

第四重循环枚举从i~i+sublen之间的每一中分割字符串的位置,考察这样分割是否能使得s1和s2对应的部分scramble得到,k从1~sublen-1;

代码如下:

 1 public class Solution {
 2     public boolean isScramble(String s1, String s2) {
 3         if(s1.length() != s2.length())
 4             return false;
 5         
 6         if(s1.length() == 0 && s2.length() == 0)
 7             return true;
 8         
 9         int n = s1.length();
10         boolean[][][] dp = new boolean[n+1][n+1][n+1];
11         for(int i = 0;i < n;i++){
12             for(int j = 0;j < n;j++)
13                 dp[1][i][j] = s1.charAt(i) == s2.charAt(j); 
14         }
15         
16         for(int sublen = 2;sublen <= n;sublen++){ 
17             for(int i = 0;i <= n-sublen;i++){
18                 for(int j = 0;j <= n-sublen;j++){
19                     dp[sublen][i][j]= false; 
20                     for(int k = 1;k<sublen && dp[sublen][i][j]== false ;k++)
21                         dp[sublen][i][j] = (dp[k][i][j]&&dp[sublen-k][i+k][j+k]) || (dp[k][i][j+sublen-k] && dp[sublen-k][i+k][j]);  
22                 }
23             }
24         }
25         return dp[n][0][0];
26     }
27 }

【leetcode刷题笔记】Scramble String,布布扣,bubuko.com

【leetcode刷题笔记】Scramble String

标签:des   style   blog   http   color   os   

原文地址:http://www.cnblogs.com/sunshineatnoon/p/3862847.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!