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)。不知道这么算是否正确,以及复杂度的分析是否正确。