Scramble String

Total Accepted: 43919 Total Submissions: 167323 Difficulty: Hard
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.

思路

朴素暴力递归解法

  • 跟二叉树层类似,层层递归即可
  • lintcode能通过 leetcode不能
public class Solution {
    public boolean isScramble(String s1, String s2) {
        if (s1 == null && s2 == null) {
            return true;
        }

        if (s1 == null || s2 == null || s1.length() != s2.length()) {
            return false;
        }

        if (s1.equals(s2)) {
            return true;
        }

        for (int i = 0; i < s1.length() - 1; i++) {
            String s11 = s1.substring(0, i + 1);
            String s12 = s1.substring(i + 1, s1.length());

            String s21 = s2.substring(0, i + 1);
            String s22 = s2.substring(i + 1, s2.length());

            String s23 = s2.substring(s2.length() - i - 1, s2.length());
            String s24 = s2.substring(0, s2.length() - i - 1);

            if ((isScramble(s11, s21) && isScramble(s12, s22)) || (isScramble(s11, s23) && isScramble(s12, s24))) {
                return true;
            }
        }

        return false;
    }
}

剪枝优化

  • 增加了判断条件
  • 如果本来字符就不同,那就不满足,就return false,很大地提高了速度,可通过leetcode
public class Solution {
    public boolean isScramble(String s1, String s2) {
        if (s1 == null && s2 == null) {
            return true;
        }

        if (s1 == null || s2 == null || s1.length() != s2.length()) {
            return false;
        }

        char[] s1Char = s1.toCharArray();
        char[] s2Char = s2.toCharArray();
        Arrays.sort(s1Char);
        Arrays.sort(s2Char);
        String new1 = new String(s1Char);
        String new2 = new String(s2Char);

        if (!new1.equals(new2)) {
            return false;
        }

        if (s1.equals(s2)) {
            return true;
        }

        for (int i = 0; i < s1.length() - 1; i++) {
            String s11 = s1.substring(0, i + 1);
            String s12 = s1.substring(i + 1, s1.length());

            String s21 = s2.substring(0, i + 1);
            String s22 = s2.substring(i + 1, s2.length());

            String s23 = s2.substring(s2.length() - i - 1, s2.length());
            String s24 = s2.substring(0, s2.length() - i - 1);

            if ((isScramble(s11, s21) && isScramble(s12, s22)) || (isScramble(s11, s23) && isScramble(s12, s24))) {
                return true;
            }
        }

        return false;
    }
}

Memorization优化

  • 写了hashmap作为memorization的优化但是没完全通过,debug了好一阵,直接引用参考资料
  • 这个key直接用的是s1 + " " + s2, value就是true or false
  • hashmap最方便,否则要使用三维数组
  • 使用三维数组的话:index1记忆S1起始地址,index2记忆S2起始地址,len 表示字符串的长度。这样我们可以用一个三维数组来记录计算过的值
  • 这个三维数组一个是N^3的复杂度,在每一个递归中,要从1-len地计算一次所有的子串,所以一共的复杂度是N^4
public class Solution {
    private boolean isScramble(String s1, String s2, Map<String, Boolean> cache) {

        if (s1.equals(s2)) return true;
        if (s1.length() <= 1) return false;
        String cacheKey = s1 + " " + s2;
        if (cache.containsKey(cacheKey)) return cache.get(cacheKey);

        boolean flag = false;
        int n = s1.length();
        for (int i = 1; i < n; i++) {
            if (isScramble(s1.substring(0, i), s2.substring(0, i), cache)
                && isScramble(s1.substring(i), s2.substring(i), cache)) {
                    flag = true;
                    break;
                }

            if (isScramble(s1.substring(0, i), s2.substring(n - i, n), cache)
                && isScramble(s1.substring(i, n), s2.substring(0, n - i), cache)) {
                    flag = true;
                    break;
                }
        }

        cache.put(cacheKey, flag);
        return flag;
    }

    public boolean isScramble(String s1, String s2) {
        if (s1.isEmpty() && s2.isEmpty()) return true;

        HashMap<String, Boolean> cache = new HashMap<String, Boolean>();
        return isScramble(s1, s2, cache);
    }
}

还有动规解法

results matching ""

    No results matching ""