87. Scramble String (Java)

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.

Example 1:

Input: s1 = "great", s2 = "rgeat"
Output: true

Example 2:

Input: s1 = "abcde", s2 = "caebd"
Output: false

 

思路:对付复杂问题的方法是从简单的特例来思考。简单情况:

  1. 如果字符串长度为1,那么必须两个字符串完全相同;
  2. 如果字符串长度为2,例如s1='ab',则s2='ab'或s2='ba'才行
  3. 如果字符串任意长度,那么可以把s1分为a1, b1两部分,s2分为a2,b2两部分。需要满足:((a1=a2)&&(b1=b2)) || ((a1=b2)&&(a2=b1)) =>可用递归
class Solution {
    public boolean isScramble(String s1, String s2) {
        if(s1.length()==1) return s1.equals(s2);
        
        String s11;
        String s12;
        String s21;
        String s22;
        for(int i = 1; i <= s1.length(); i++){
            s11 = s1.substring(0, i);
            s12 = s1.substring(i);
            s21 = s2.substring(0,i);
            s22 = s2.substring(i);
            if(isScramble(s11,s21) && isScramble(s12,s22)) return true;
            if(isScramble(s11,s22) && isScramble(s12,s21)) return true;
        }
        return false;
    }
}

Result: Time Limit Exceeded

解决方法:动态规划。三维状态dp[i][j][k],前两维分别表示s1和s2的下标起始位置,k表示子串的长度。dp[i][j][k]=true表示s1(i, i+k-1)和s2(j, j+k-1)是scramble。

结合递归法中的逻辑,dp[i][j][k]=true的条件是s1(i, i+split-1)=s2(j, j+split-1) && s1(i+split, i+k-1) = s2(j+split, j+k-1) 或者 s1(i, i+split-1)=s2(j+k-split, j+k-1) && s1(i+split, i+k-1) = s2(j, j+k-split-1)

所以状态转移方程是:如果dp[i][j][split] = true && dp[i+split][j+split][k-split] = true 或者 dp[i][j+k-split][split]=true && dp[i+split][j][k-split]=true,那么dp[i][j][k]=true

初始状态:当k=1的时候dp[i][j][1]=true的条件是s1(i)=s2(j)

class Solution {
    public boolean isScramble(String s1, String s2) {
        if(s1.length()== 0 || s1.equals(s2)) return true;
        
        boolean dp[][][] = new boolean[s1.length()][s1.length()][s1.length()+1];
        
        //initial state
        for(int i = 0; i < s1.length(); i++){
            for(int j = 0; j < s2.length(); j++){
                dp[i][j][1] = s1.charAt(i)==s2.charAt(j);
            }
        }
        
        //state transfer
        for(int k = 2; k <= s1.length(); k++){
            for(int i = 0; i+k-1 < s1.length(); i++){
                for(int j = 0; j+k-1 < s1.length(); j++){
                    for(int split = 1; split < k; split++){
                        //如果dp[i][j][split] = true && dp[i+split][j+split][k-split] = true 或者 dp[i][j+k-split][split]=true && dp[i+split][j][k-split]=true,那么dp[i][j][k]=true
                        if((dp[i][j][split] && dp[i+split][j+split][k-split]) || (dp[i][j+k-split][split] && dp[i+split][j][k-split])){
                            dp[i][j][k] = true;
                            break;
                        }
                    }
                }
            }
        }     
        return dp[0][0][s1.length()];
    }
}

 

posted on 2019-07-04 19:37  joannae  阅读(163)  评论(0编辑  收藏  举报

导航