Friday, September 27, 2013

Scramble String

Q:
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.

A:
 首先,我们想到的是递归调用
代码如下:
public class Solution {
       public boolean isScramble(String s1, String s2) {
        // idea: assume s1 is original string , and s2 is the scrambled one
        // if scrambled, it must be that it is first k letters of s2 is the
        // scramble of first k letters of s1
        if(s1.length() != s2.length())
            return false;
        if(s1.length() == 1){
            return s1.charAt(0) == s2.charAt(0);
        }
        for(int i = 1;i< s1.length()-1; i++){ // i is the position , belongs to left part
            boolean left1 = isScramble(s1.substring(0,i+1),s2.substring(0,i+1));
            boolean right1 = isScramble(s1.substring(i+1),s2.substring(i+1));
            
            boolean left2 = isScramble(s1.substring(0,i+1),s2.substring(s2.length() - i));
            boolean right2 = isScramble(s1.substring(s1.length() - i),s2.substring(0,i+1));
            
            if(left1 && right1 || left2 && right2)
                return true;
        }
        return false;
       }
}

当然,结果是太慢 TLE


-----------下面是非递归的方法。  ------------------


主要错误在于: 对每个position, 我们有两个选择, 或者在这个点scramble或者在这里继续向两边分。

public class ScrambleString {
    public boolean isScramble(String s1, String s2) {
        // idea: assume s1 is original string , and s2 is the scrambled one
        // if scrambled, it must be that it is first k letters of s2 is the
        // scramble of first k letters of s1
        if (s1.length() != s2.length())
            return false;
        if (s1.length() == 1) { // s2.length == 1
            if (s1.equals(s2)) {
                return true;
            } else {
                return false;
            }
        }
        // NOW string length >= 1
        int n = s1.length();
        // for the first k letters, check it is the left scramble.
        if (s1.equals(s2)) {
            return true;
        }
        // find a split at split index i
        // At position i, we have two choice,
        // 1) permute here,
        // 2) continue split at i, left to left, right to right
        for (int i = 1; i < s1.length(); i++) {// left and right should not
                                                // be empty
            // CASE 1: we scramble at this position
            // if left of s1 == right of s2, they are the same, we can return
            // true
            String s1LeftI = s1.substring(0, i);
            String s1AfterI = s1.substring( i);
            // if left of s1 is the same with right of s2, and vice versa
            String s2MatchLeftS1 = s2.substring(n - i);
            String s2MatchRightS1 = s2.substring(0, n - i);
            if (isPermuation(s1LeftI, s2MatchLeftS1)&& isPermuation(s1AfterI, s2MatchRightS1)) {
                boolean left = isScramble(s1LeftI, s2MatchLeftS1);
                boolean right = isScramble(s1AfterI, s2MatchRightS1);
                if (left && right) {
                    return true;
                }
            }
            String s2LeftI = s2.substring(0, i);
            String s2AfterI = s2.substring( i);
            if (isPermuation(s1LeftI, s2LeftI)&& isPermuation(s1AfterI, s2AfterI)) {
                // if left of s1 is permuation of ( left of s2), and
                boolean left = isScramble(s1LeftI,
                        s2LeftI);
                boolean right = isScramble(s1AfterI, s2AfterI);
                if (left && right) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isPermuation(String str1, String str2) {
        char[] a = str1.toCharArray();
        char[] b = str2.toCharArray();
        Arrays.sort(a);
        Arrays.sort(b);
        return Arrays.equals(a,b);
    }
}


Mistakes:
1: 光顾的左右分区了,没有考虑,交换过来的情况。
2: 自己的命名挺ugly的。呵呵

Learned:
1: java 中, Arrays.sort()是基于int (或者double)类型的   quicksort实现。
因此,char [] 也可以直接调用
--------------------------------第二遍-----------思想同上--------
public class Solution {
 public boolean isScramble(String s1, String s2) {
        // idea: assume s1 is original string , and s2 is the scrambled one
        // if scrambled, it must be that it is first k letters of s2 is the
        // scramble of first k letters of s1
        if (s1.length() != s2.length())
            return false;
        if (s1.length() == 1) {
            return s1.charAt(0) == s2.charAt(0);
        }
        char[] ch1 = s1.toCharArray();
        char[] ch2 = s2.toCharArray();
        Arrays.sort(ch1);
        Arrays.sort(ch2);
        // check whether ch1 == ch2
        if(Arrays.equals(ch1,ch2)==false)
            return false;
        // now, characters are the same, we check their scrambling
        for (int leftLen = 1; leftLen < s1.length(); leftLen++) { // i is the length of left
                                                    // part of s1
            String leftS1 = s1.substring(0, leftLen );
            String rightS1 = s1.substring(leftLen );
            // if left i part match s1
            String leftS2 = s2.substring(0, leftLen);
            String rightS2 = s2.substring(leftLen );

            if (isScramble(leftS1, leftS2) && isScramble(rightS1, rightS2))
                return true;

            // now test case 2, where s2 is scrambled to the right part
            String s2MatchLeftS1 = s2.substring(s2.length() - leftLen);
            String s2MatchRightS2 = s2.substring(0, s2.length() - leftLen);

            if (isScramble(leftS1, s2MatchLeftS1) && isScramble(rightS1, s2MatchRightS2))
                return true;
        }
        return false;
    }
}
------------------------------3 rd -----------------思路同第二遍----------------
Error:
1:      很傻比, 不知道,s1的左边要跟s2的右边比较,  反而去左边和左边比较,右边和右边比较去了。  哎,SB
2:     脑子被驴踢了,哎,竟然能犯这个SB 错误。  自己看看吧。 为什么下面这样写不对。

import java.util.Arrays;

public class Solution {
    public boolean isScramble(String s1, String s2) {
        // use recursive idea, but instead of trying every possible chars,
        if (s1.length() != s2.length())
            return false;
        int n = s1.length();
        if (n == 0 || s1.equals(s2))
            return true;
        // now beginning and end is not equal, we need do left right matching
        for (int i = 1; i < n; i++) {
            String s1Left = s1.substring(0, i);
            String s1Right = s1.substring(i);

            // test whether left of s1 equals left of s2
            String s2Left = s2.substring(0, i);
            String s2Right = s2.substring(i);
            if (isEqualAfterSort(s1Left, s2Left))
                return isScramble(s1Left, s2Left)
                        && isScramble(s1Right, s2Right);

            s2Left = s2.substring(0, n - i);
            s2Right = s2.substring(n - i);
            // if left of s1 equals to right of s2
            if (isEqualAfterSort(s1Left, s2Right))
                return isScramble(s1Left, s2Right)
                        && isScramble(s1Right, s2Left);
        }
        return false;
    }

    private boolean isEqualAfterSort(String str1, String str2) {
        char[] arr1 = str1.toCharArray();
        char[] arr2 = str2.toCharArray();
        Arrays.sort(arr1);
        Arrays.sort(arr2);
        String ss1 = new String(arr1);
        String ss2 = new String(arr2);
        return ss1.equals(ss2);
    }
}










揭示错误2:  因为,即使两个sort后是一样的,但依然不能保证是scramble的。 因此,不能直接返回结果, 而应该是match之后,如果是true,才能返回

No comments:

Post a Comment