Scramble String

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.

开始的思路是类似于二叉树的做法,发现不好找左右子的划分,各种WA,感觉是动态规划,但是我对动态规划不熟悉,没找出状态方程。搜了搜网上的解法,整理了一下:

设f[n][i][j]表示s1中从i位置开始长度为n的串是否与s2中从j位置开始长度为n的串互为scramble string,则有状态方程如下:

f[n][i][j] = f[n][i][j] || (f[k][i][j] && f[n-k][i+k][j+k]) || (f[k][i][j+n-k] && f[n-k][i+k][j])      k从1到n-1

由上述方程可以看出,计算f[n][i][j]时,n之前的已经计算过,i和j之后的已经计算过,因此,递归时候n++,i--,j--。

代码如下:

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

复杂度不会算了,从代码的循环上来看是O(n^4),空间复杂度是O(n^3)

感觉还可以改一改,有一个思路,没有具体实现,不知道是否可行

每次在串s1中取子串0到i(i从1到n),与s2中子串的前i个或后i个比较,若字符相同,递归判断是否是scramble string,比较字符相同就先排序,然后比较,排序为O(nlgn),比较为O(n),因此整体为O(nlgn),每次从1到n,因此,为O(n^2*lgn),每次最少可以将s1长度减1,因此,最多递归n次,因此,整体复杂度为O(n^3*lgn)。不知道这么算是否正确,以及复杂度的分析是否正确。

posted @ 2014-05-28 16:02  秋风一片叶  阅读(178)  评论(0编辑  收藏  举报