https://leetcode.com/problems/scramble-string

Given a strings1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.

Below is one possible representation ofs1="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.

To scramble the string, we may choose any non-leaf node and swap its two children.

题眼:也就是假如 str1 和 str2 是scramble 得到的, 那么 就相当于 把str1 分成 str1_Lstr1_R, 把str2 分成 str2_Lstr2_R.

那么

1 要么 str1_L is a scrambled string of str2_L && str1_R is a scrambled string of str2_R

2 要么 str1_L is a scrambled string of str2_R && str1_R is a scrambled string of str2_L (经过了一次swap children)

method1: 自然可以得到递归 dfs 暴力解法 (但是有助于思路): ==> 192 / 282 test cases passed.

    public boolean isScramble(String s1, String s2) {
        // corner case
        if (s1 == null || s2 == null) {
            return s1 == s2;
        }
        if (s1.length() == 0 || s2.length() == 0) {
            return s1.length() == s2.length();
        }
        // quick fail
        if (s1.length() != s2.length()) {
            return false;
        }

        int n = s1.length();

        if (n == 1) {
            return s1.equals(s2);
        }
        for (int l = 1; l < n; ++l) {
            // case 1
            if (isScramble(s1.substring(0, l), s2.substring(0, l)) && isScramble(s1.substring(l), s2.substring(l))) {
                return true;
            }
            // case 2
            if (isScramble(s1.substring(0, l), s2.substring(n - l)) && isScramble(s1.substring(l), s2.substring(0, n - l))) {
                return true;
            }
        }
        return false;
    }

method2: 不用substring, 利用two pointers 表示substring : ==> 208 / 282 test cases passed.

    public boolean isScramble(String s1, String s2) {
        // corner case handle
        if (s1 == null || s2 == null) {
            return s1 == s2;
        }
        if (s1.length() == 0 || s2.length() == 0) {
            return s1.length() == s2.length();
        }
        if (s1.length() != s2.length()) {
            return false;
        }

        int n = s1.length();
        return dfs(s1.toCharArray(), 0, n - 1, s2.toCharArray(), 0, n - 1);
    }

    private boolean dfs(char[] str1, int s1, int e1, char[] str2, int s2, int e2) {
        // try every possible cases
        if (s1 == e1) {
            return str1[s1] == str2[s2];
        }
        int n = e1 - s1 + 1;
        for (int l = 1; l < n; ++l) {
            if (dfs(str1, s1, s1 + l - 1, str2, s2, s2 + l - 1) && dfs(str1, s1 + l, e1, str2, s2 + l, e2)) {
                return true;
            }

            if (dfs(str1, s1, s1 + l - 1, str2, e2 - l + 1, e2) && dfs(str1, s1 + l, e1, str2, s2, e2 - l)) {
                return true;
            }
        }
        return false;
    }

method3: 超时是因为重复计算子结构 -> memoization (记忆化搜索) ==》 Accepted

仅仅就是多了一个 Boolean[][][] mem;

public class Solution {
    Boolean[][][] mem;
    public boolean isScramble(String s1, String s2) {
        // corner case handle
        if (s1 == null || s2 == null) {
            return s1 == s2;
        }
        if (s1.length() == 0 || s2.length() == 0) {
            return s1.length() == s2.length();
        }
        if (s1.length() != s2.length()) {
            return false;
        }

        int n = s1.length();
        mem = new Boolean[n + 1][n][n];
        return dfs(s1.toCharArray(), 0, n - 1, s2.toCharArray(), 0, n - 1);
    }

    private boolean dfs(char[] str1, int s1, int e1, char[] str2, int s2, int e2) {
        // try every possible cases
        if (s1 == e1) {
            mem[1][s1][s2] = (str1[s1] == str2[s2]);
            return mem[1][s1][s2];
        }
        int n = e1 - s1 + 1;
        if (mem[n][s1][s2] != null) {
            return mem[n][s1][s2];
        }
        for (int l = 1; l < n; ++l) {
            if (dfs(str1, s1, s1 + l - 1, str2, s2, s2 + l - 1) && dfs(str1, s1 + l, e1, str2, s2 + l, e2)) {
                mem[n][s1][s2] = true;
                return true;
            }

            if (dfs(str1, s1, s1 + l - 1, str2, e2 - l + 1, e2) && dfs(str1, s1 + l, e1, str2, s2, e2 - l)) {
                mem[n][s1][s2] = true;
                return true;
            }
        }
        mem[n][s1][s2] = false;
        return false;
    }
}

method4: 既然可以用memoization (top down)那么也肯定可以用DP (bottom up)

完全可以对照着上面快速写出来

public class Solution {
    public boolean isScramble(String s1, String s2) {
        // corner case handle
        if (s1 == null || s2 == null) {
            return s1 == s2;
        }
        if (s1.length() == 0 || s2.length() == 0) {
            return s1.length() == s2.length();
        }
        if (s1.length() != s2.length()) {
            return false;
        }

        int n = s1.length();
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        boolean[][][] mem = new boolean[n + 1][n][n];

        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                mem[1][i][j] = str1[i] == str2[j];
            }
        }

        for (int ln = 2; ln <= n; ++ln) {
            for(int i = 0; i <= n - ln; ++i) {
                for (int j = 0; j <= n - ln; ++j) {
                    for (int l = 1; l < ln; ++l) {
                        if (mem[l][i][j] && mem[ln-l][i+l][j+l]) {
                            mem[ln][i][j] = true;
                        }
                        if (mem[l][i][j+ln-l] && mem[ln-l][i+l][j]) {
                            mem[ln][i][j] = true;
                        }
                    }
                }
            }
        }
        return mem[n][0][0];
    }
}

results matching ""

    No results matching ""