Scramble String
Problem Statement :
We can scramble a string s to get a string t using the following algorithm: If the length of the string is 1, stop. If the length of the string is > 1, do the following: Split the string into two non-empty substrings at a random index, i.e., if the string is s, divide it to x and y where s = x + y. Randomly decide to swap the two substrings or to keep them in the same order. i.e., after this step, s may become s = x + y or s = y + x. Apply step 1 recursively on each of the two substrings x and y. Given two strings s1 and s2 of the same length, return true if s2 is a scrambled string of s1, otherwise, return false. Example 1: Input: s1 = "great", s2 = "rgeat" Output: true Explanation: One possible scenario applied on s1 is: "great" --> "gr/eat" // divide at random index. "gr/eat" --> "gr/eat" // random decision is not to swap the two substrings and keep them in order. "gr/eat" --> "g/r / e/at" // apply the same algorithm recursively on both substrings. divide at random index each of them. "g/r / e/at" --> "r/g / e/at" // random decision was to swap the first substring and to keep the second substring in the same order. "r/g / e/at" --> "r/g / e/ a/t" // again apply the algorithm recursively, divide "at" to "a/t". "r/g / e/ a/t" --> "r/g / e/ a/t" // random decision is to keep both substrings in the same order. The algorithm stops now, and the result string is "rgeat" which is s2. As one possible scenario led s1 to be scrambled to s2, we return true. Example 2: Input: s1 = "abcde", s2 = "caebd" Output: false Example 3: Input: s1 = "a", s2 = "a" Output: true
Solution :
Solution in C :
static char *s_lookup, *s_s1, *s_s2;
static int s_len;
int CheckSramble(char *current, char *target, int len)
{
char *flag=s_lookup+((current-s_s1)*s_len+target-s_s2)*s_len+len;
if(*flag!=-1) return *flag;
if(!memcmp(current, target, len)) return *flag=1;
int char_table_s1_head[26]={};
int char_table_s2_head[26]={};
int char_table_s2_tail[26]={};
for(int i=1;i<len;i++)
{
char_table_s1_head[current[i-1]-'a']++;
char_table_s2_head[target[i-1]-'a']++;
if(!memcmp(char_table_s1_head, char_table_s2_head, sizeof(char_table_s1_head)))
if(CheckSramble(current, target, i) && CheckSramble(current+i, target+i, len-i))
return *flag=1;
char_table_s2_tail[target[len-i]-'a']++;
if(!memcmp(char_table_s1_head, char_table_s2_tail, sizeof(char_table_s1_head)))
if(CheckSramble(current+i, target, len-i) && CheckSramble(current, target+len-i, i))
return *flag=1;
}
return *flag=0;
}
bool isScramble(char * s1, char * s2){
int len=strlen(s1);
int char_table_s1[26]={};
int char_table_s2[26]={};
for(int i=0;i<len;i++)
{
char_table_s1[s1[i]-'a']++;
char_table_s2[s2[i]-'a']++;
}
if(memcmp(char_table_s1, char_table_s2, sizeof(char_table_s1))) return false;
s_len=len+1;
s_lookup=(char*)malloc(s_len*s_len*s_len);
memset(s_lookup, -1, s_len*s_len*s_len);
s_s1=s1, s_s2=s2;
bool ret=CheckSramble(s1, s2, len);
free(s_lookup);
return ret;
}
Solution in C++ :
class Solution {
public:
// checks if s2 is scrambled form of s1
/*
The idea is to find a position in string s1, from where scrambling must have
started to create s2. So if k is the position, then s1[0-k] and s1[k+1, N-1]
were the last scramble op. We do this recursively for the smaller substrings.
*/
bool isScrambled(int s1_start, int s1_end, int s2_start, int s2_end,
string& s1, string& s2, unordered_map<string, bool>& dp) {
// create the current position combination
string curr_cmb = to_string(s1_start) + ',' + to_string(s1_end) +
',' + to_string(s2_start) + ',' + to_string(s2_end);
// check if the values is in cache
auto it = dp.find(curr_cmb);
if(it != dp.end())
return dp[curr_cmb];
// base cases
if(s1_end < s1_start || s2_end < s2_start)
return false;
// if the size of two strings is diff, then scrambling not poss
if(s1_end - s1_start != s2_end - s2_start)
return false;
// if the two substrings match, then they are scrambled
if(s1.substr(s1_start, s1_end - s1_start + 1) == s2.substr(s2_start, s2_end - s2_start + 1))
return true;
// check if the two substrings contains the same set of chars
vector<int> char_freq(256, 0);
for(int i = 0; i <= s1_end - s1_start; i++)
char_freq[s1[s1_start + i]-'a']++, char_freq[s2[s2_start + i]-'a']--;
for(int i = 0; i < 256; i++)
if(char_freq[i])
return false;
// find a position which is the potential scramble point
for(int k = 0; k < (s1_end - s1_start); k++) {
// check for s1[start: k], s2[start:k] and s1[k+1 : end], s2[k+1 : end]
if(isScrambled(s1_start, s1_start + k, s2_start, s2_start + k, s1, s2, dp) &&
isScrambled(s1_start + k + 1, s1_end, s2_start + k + 1, s2_end, s1, s2, dp))
return dp[curr_cmb] = true;
// Now incase of s2, maybe scramble opertation was performed at k, so
// now check if the other half of s2
// check for s1[start: k], s2[end - k : end] and s1[k+1 : end], s2[s : end - k - 1]
if(isScrambled(s1_start, s1_start + k, s2_end - k, s2_end, s1, s2, dp) &&
isScrambled(s1_start + k + 1, s1_end, s2_start, s2_end - k - 1, s1, s2, dp))
return dp[curr_cmb] = true;
}
return dp[curr_cmb] = false;
}
bool isScramble(string s1, string s2) {
// DP cache: saves the result of (s1_start, s1_end, s2_start, s2_end) cmb
unordered_map<string, bool> dp;
return isScrambled(0, s1.size()-1, 0, s2.size()-1, s1, s2, dp);
}
};
Solution in Java :
public class Solution {
public boolean isScramble(String s1, String s2) {
if (s1.length() != s2.length()) return false;
int len = s1.length();
/**
* Let F(i, j, k) = whether the substring S1[i..i + k - 1] is a scramble of S2[j..j + k - 1] or not
* Since each of these substrings is a potential node in the tree, we need to check for all possible cuts.
* Let q be the length of a cut (hence, q < k), then we are in the following situation:
*
* S1 [ x1 | x2 ]
* i i + q i + k - 1
*
* here we have two possibilities:
*
* S2 [ y1 | y2 ]
* j j + q j + k - 1
*
* or
*
* S2 [ y1 | y2 ]
* j j + k - q j + k - 1
*
* which in terms of F means:
*
* F(i, j, k) = for some 1 <= q < k we have:
* (F(i, j, q) AND F(i + q, j + q, k - q)) OR (F(i, j + k - q, q) AND F(i + q, j, k - q))
*
* Base case is k = 1, where we simply need to check for S1[i] and S2[j] to be equal
* */
boolean [][][] F = new boolean[len][len][len + 1];
for (int k = 1; k <= len; ++k)
for (int i = 0; i + k <= len; ++i)
for (int j = 0; j + k <= len; ++j)
if (k == 1)
F[i][j][k] = s1.charAt(i) == s2.charAt(j);
else for (int q = 1; q < k && !F[i][j][k]; ++q) {
F[i][j][k] = (F[i][j][q] && F[i + q][j + q][k - q]) || (F[i][j + k - q][q] && F[i + q][j][k - q]);
}
return F[0][0][len];
}
}
Solution in Python :
class Solution(object):
def isScramble(self, s1, s2):
"""
:type s1: str
:type s2: str
:rtype: bool
"""
if s1 == s2:
return True
if len(s1) != len(s2):
return False
# Check both strings have same count of letters
count1 = collections.defaultdict(int)
count2 = collections.defaultdict(int)
for c1, c2 in zip(s1, s2):
count1[c1] += 1
count2[c2] += 1
if count1 != count2: return False
# Iterate through letters and check if it results in a partition of
# string 1 where the collection of letters are the same
# on the left (non-swapped) or right (swapped) sides of string 2
# Then we recursively check these partitioned strings to see if they are scrambled
lcount1 = collections.defaultdict(int) # s1 count from left
lcount2 = collections.defaultdict(int) # s2 count from left
rcount2 = collections.defaultdict(int) # s2 count from right
for i in xrange(len(s1) - 1):
lcount1[s1[i]] += 1
lcount2[s2[i]] += 1
rcount2[s2[len(s1) - 1 - i]] += 1
if lcount1 == lcount2: # Left sides of both strings have same letters
if self.isScramble(s1[:i + 1], s2[:i + 1]) and \
self.isScramble(s1[i + 1:], s2[i + 1:]):
return True
elif lcount1 == rcount2: # Left side of s1 has same letters as right side of s2
if self.isScramble(s1[:i + 1], s2[-(i + 1):]) and \
self.isScramble(s1[i + 1:], s2[:-(i + 1)]):
return True
return False
View More Similar Problems
Tree: Postorder Traversal
Complete the postorder function in the editor below. It received 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's postorder traversal as a single line of space-separated values. Input Format Our test code passes the root node of a binary tree to the postorder function. Constraints 1 <= Nodes in the tree <= 500 Output Format Print the
View Solution →Tree: Inorder Traversal
In this challenge, you are required to implement inorder traversal of a tree. Complete the inorder function in your editor below, which has 1 parameter: a pointer to the root of a binary tree. It must print the values in the tree's inorder traversal as a single line of space-separated values. Input Format Our hidden tester code passes the root node of a binary tree to your $inOrder* func
View Solution →Tree: Height of a Binary Tree
The height of a binary tree is the number of edges between the tree's root and its furthest leaf. For example, the following binary tree is of height : image Function Description Complete the getHeight or height function in the editor. It must return the height of a binary tree as an integer. getHeight or height has the following parameter(s): root: a reference to the root of a binary
View Solution →Tree : Top View
Given a pointer to the root of a binary tree, print the top view of the binary tree. The tree as seen from the top the nodes, is called the top view of the tree. For example : 1 \ 2 \ 5 / \ 3 6 \ 4 Top View : 1 -> 2 -> 5 -> 6 Complete the function topView and print the resulting values on a single line separated by space.
View Solution →Tree: Level Order Traversal
Given a pointer to the root of a binary tree, you need to print the level order traversal of this tree. In level-order traversal, nodes are visited level by level from left to right. Complete the function levelOrder and print the values in a single line separated by a space. For example: 1 \ 2 \ 5 / \ 3 6 \ 4 F
View Solution →Binary Search Tree : Insertion
You are given a pointer to the root of a binary search tree and values to be inserted into the tree. Insert the values into their appropriate position in the binary search tree and return the root of the updated binary tree. You just have to complete the function. Input Format You are given a function, Node * insert (Node * root ,int data) { } Constraints No. of nodes in the tree <
View Solution →