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: trueExample 2:
Input: s1 = "abcde", s2 = "caebd" Output: false
扰乱字符串。题意是给一个string s1,这个string被表示成一个二叉树。在树的叶节点,每个字母会被分到二叉树的每一个最小的分支上自成一支。
如上例子,great和rgeat是互为scramble string的。这题给的tag是DP但是DP的实现是三维的,几乎不可能在面试过程中完美实现。这里我给出的是递归解法,比较直观。
时间O(n!) - 我其实不是很确定
空间O(n) - 因为递归用到栈空间
JavaScript实现
1 /** 2 * @param {string} s1 3 * @param {string} s2 4 * @return {boolean} 5 */ 6 var isScramble = function(s1, s2) { 7 if (s1 === s2) return true; 8 const letters = new Array(128).fill(0); 9 const a = 'a'.charCodeAt(0); 10 for (let i = 0; i < s1.length; i++) { 11 letters[s1.charCodeAt(i) - a]++; 12 letters[s2.charCodeAt(i) - a]--; 13 } 14 for (let i = 0; i < 128; i++) { 15 if (letters[i] !== 0) return false; 16 } 17 for (let i = 1; i < s1.length; i++) { 18 if (isScramble(s1.substring(0, i), s2.substring(0, i)) && isScramble(s1.substring(i), s2.substring(i))) 19 return true; 20 if ( 21 isScramble(s1.substring(0, i), s2.substring(s2.length - i)) && 22 isScramble(s1.substring(i), s2.substring(0, s2.length - i)) 23 ) 24 return true; 25 } 26 return false; 27 };
Java实现 - 超时
1 class Solution { 2 public boolean isScramble(String s1, String s2) { 3 // corner case 4 if (s1 == null || s2 == null) { 5 return false; 6 } 7 if (s1.equals(s2)) { 8 return true; 9 } 10 // normal case 11 int[] letters = new int[26]; 12 int len = s1.length(); 13 for (int i = 0; i < len; i++) { 14 letters[s1.charAt(i) - 'a']++; 15 letters[s2.charAt(i) - 'a']--; 16 } 17 for (int i = 0; i < 26; i++) { 18 if (letters[i] != 0) { 19 return false; 20 } 21 } 22 for (int i = 1; i < len; i++) { 23 if (isScramble(s1.substring(0, i), s2.substring(0, i)) && isScramble(s1.substring(i), s2.substring(i))) { 24 return true; 25 } 26 if (isScramble(s1.substring(0, i), s2.substring(len - i)) && isScramble(s1.substring(i), s2.substring(0, len - i))) { 27 return true; 28 } 29 } 30 return false; 31 } 32 }
Java另一种带memorization的实现
1 class Solution { 2 HashMap<String, Boolean> map = new HashMap<>(); 3 4 public boolean isScramble(String s1, String s2) { 5 StringBuilder sb = new StringBuilder(); 6 sb.append(s1); 7 sb.append(s2); 8 String key = sb.toString(); 9 10 if (map.containsKey(key)) { 11 return map.get(key); 12 } 13 14 if (s1.equals(s2)) { 15 map.put(key, true); 16 return true; 17 } 18 19 int[] letters = new int[26]; 20 for (int i = 0; i < s1.length(); i++) { 21 letters[s1.charAt(i) - 'a']++; 22 letters[s2.charAt(i) - 'a']--; 23 } 24 for (int i = 0; i < 26; i++) { 25 if (letters[i] != 0) { 26 map.put(key, false); 27 return false; 28 } 29 } 30 31 for (int i = 1; i < s1.length(); i++) { 32 if (isScramble(s1.substring(0, i), s2.substring(0, i)) && isScramble(s1.substring(i), s2.substring(i))) { 33 map.put(key, true); 34 return true; 35 } 36 37 if (isScramble(s1.substring(0, i), s2.substring(s1.length() - i)) 38 && isScramble(s1.substring(i), s2.substring(0, s1.length() - i))) { 39 map.put(key, true); 40 return true; 41 } 42 } 43 44 map.put(key, false); 45 return false; 46 } 47 }