Check if a string is a scrambled form of another string
Given two strings S1 and S2 of equal length, the task is to determine if S2 is a scrambled form of S1.
Scrambled string:
Given string str, we can represent it as a binary tree by partitioning it into two non-empty substrings recursively.
Note: Scrambled string is not same as an Anagram
Below is one possible representation of str = “coder”:
coder
/ \
co der
/ \ / \
c o d er
/ \
e r
To scramble the string, we may choose any non-leaf node and swap its two children.
Suppose, we choose the node “co” and swap its two children, it produces a scrambled string “ocder”.
ocder
/ \
oc der
/ \ / \
o c d er
/ \
e r
Thus, “ocder” is a scrambled string of “coder”.
Similarly, if we continue to swap the children of nodes “der” and “er”, it produces a scrambled string “ocred”.
ocred
/ \
oc red
/ \ / \
o c re d
/ \
r e
Thus, “ocred” is a scrambled string of “coder”.
Examples:
Input: S1=”coder”, S2=”ocder”
Output: Yes
Explanation:
“ocder” is a scrambled form of “coder”
Input: S1=”abcde”, S2=”caebd”
Output: No
Explanation:
“caebd” is not a scrambled form of “abcde”
Approach
In order to solve this problem, we are using Divide and Conquer approach.
Given two strings of equal length (say n+1), S1[0…n] and S2[0…n]. If S2 is a scrambled form of S1, then there must exist an index i such that at least one of the following conditions is true:
- S2[0…i] is a scrambled string of S1[0…i] and S2[i+1…n] is a scrambled string of S1[i+1…n].
- S2[0…i] is a scrambled string of S1[n-i…n] and S2[i+1…n] is a scrambled string of S1[0…n-i-1].
Note: An optimization step to consider here is to check beforehand if the two strings are anagrams of each other. If not, it indicates that the strings contain different characters and can’t be a scrambled form of each other.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool isScramble(string S1, string S2)
{
if (S1.length() != S2.length()) {
return false ;
}
int n = S1.length();
if (n == 0) {
return true ;
}
if (S1 == S2) {
return true ;
}
string copy_S1 = S1, copy_S2 = S2;
sort(copy_S1.begin(), copy_S1.end());
sort(copy_S2.begin(), copy_S2.end());
if (copy_S1 != copy_S2) {
return false ;
}
for ( int i = 1; i < n; i++) {
if (isScramble(S1.substr(0, i), S2.substr(0, i))
&& isScramble(S1.substr(i, n - i),
S2.substr(i, n - i))) {
return true ;
}
if (isScramble(S1.substr(0, i),
S2.substr(n - i, i))
&& isScramble(S1.substr(i, n - i),
S2.substr(0, n - i))) {
return true ;
}
}
return false ;
}
int main()
{
string S1 = "coder" ;
string S2 = "ocred" ;
if (isScramble(S1, S2)) {
cout << "Yes" ;
}
else {
cout << "No" ;
}
return 0;
}
|
Java
import java.util.*;
class GFG{
static boolean isScramble(String S1,
String S2)
{
if (S1.length() != S2.length())
{
return false ;
}
int n = S1.length();
if (n == 0 )
{
return true ;
}
if (S1.equals(S2))
{
return true ;
}
char [] tempArray1 = S1.toCharArray();
char [] tempArray2 = S2.toCharArray();
Arrays.sort(tempArray1);
Arrays.sort(tempArray2);
String copy_S1 = new String(tempArray1);
String copy_S2 = new String(tempArray2);
if (!copy_S1.equals(copy_S2))
{
return false ;
}
for ( int i = 1 ; i < n; i++)
{
if (isScramble(S1.substring( 0 , i),
S2.substring( 0 , i)) &&
isScramble(S1.substring(i, n),
S2.substring(i, n)))
{
return true ;
}
if (isScramble(S1.substring(n - i, n),
S2.substring( 0 , i)) &&
isScramble(S1.substring( 0 , n - i),
S2.substring(i, n)))
{
return true ;
}
}
return false ;
}
public static void main(String[] args)
{
String S1 = "coder" ;
String S2 = "ocred" ;
if (isScramble(S1, S2))
{
System.out.println( "Yes" );
}
else
{
System.out.println( "No" );
}
}
}
|
Python3
def isScramble(S1: str , S2: str ):
if len (S1) ! = len (S2):
return False
n = len (S1)
if not n:
return True
if S1 = = S2:
return True
if sorted (S1) ! = sorted (S2):
return False
for i in range ( 1 , n):
if (isScramble(S1[:i], S2[:i]) and
isScramble(S1[i:], S2[i:])):
return True
if (isScramble(S1[ - i:], S2[:i]) and
isScramble(S1[: - i], S2[i:])):
return True
return False
if __name__ = = "__main__" :
S1 = "coder"
S2 = "ocred"
if (isScramble(S1, S2)):
print ( "Yes" )
else :
print ( "No" )
|
C#
using System;
using System.Collections.Generic;
class GFG {
static bool isScramble( string S1, string S2)
{
if (S1.Length != S2.Length)
{
return false ;
}
int n = S1.Length;
if (n == 0)
{
return true ;
}
if (S1.Equals(S2))
{
return true ;
}
char [] tempArray1 = S1.ToCharArray();
char [] tempArray2 = S2.ToCharArray();
Array.Sort(tempArray1);
Array.Sort(tempArray2);
string copy_S1 = new string (tempArray1);
string copy_S2 = new string (tempArray2);
if (!copy_S1.Equals(copy_S2))
{
return false ;
}
for ( int i = 1; i < n; i++)
{
if (isScramble(S1.Substring(0, i),
S2.Substring(0, i)) &&
isScramble(S1.Substring(i, n - i),
S2.Substring(i, n - i)))
{
return true ;
}
if (isScramble(S1.Substring(0, i),
S2.Substring(n - i, i)) &&
isScramble(S1.Substring(i, n - i),
S2.Substring(0, n - i)))
{
return true ;
}
}
return false ;
}
static void Main()
{
string S1 = "coder" ;
string S2 = "ocred" ;
if (isScramble(S1, S2))
{
Console.WriteLine( "Yes" );
}
else
{
Console.WriteLine( "No" );
}
}
}
|
Javascript
<script>
function isScramble(S1, S2)
{
if (S1.length != S2.length)
{
return false ;
}
let n = S1.length;
if (n == 0)
{
return true ;
}
if (S1 == S2)
{
return true ;
}
let tempArray1 = S1.split(' ');
let tempArray2 = S2.split(' ');
tempArray1.sort();
tempArray2.sort();
let copy_S1 = tempArray1.join( "" );
let copy_S2 = tempArray2.join( "" );
if (copy_S1 != copy_S2)
{
return false ;
}
for (let i = 1; i < n; i++)
{
if (isScramble(S1.substring(0, i),
S2.substring(0, i)) &&
isScramble(S1.substring(i, i + n),
S2.substring(i, i + n)))
{
return true ;
}
if (isScramble(S1.substring(n - i, n - i + n),
S2.substring(0, i)) &&
isScramble(S1.substring(0, n - i),
S2.substring(i, i + n)))
{
return true ;
}
}
return false ;
}
let S1 = "coder" ;
let S2 = "ocred" ;
if (isScramble(S1, S2))
{
document.write( "Yes" );
}
else
{
document.write( "No" );
}
</script>
|
Time Complexity: O(2^k + 2^(n-k)), where k and n-k are the length of the two substrings.
Auxiliary Space: O(2^N), recursion stack.
Dynamic Programming Solution: The above recursive Code can be optimized by storing Boolean values of substrings in an unordered map, so if the same substrings have to be checked again we can easily just get value from the map instead of performing function calls.
Memoized Code:
C++
#include <bits/stdc++.h>
using namespace std;
unordered_map<string, bool > mp;
bool isScramble(string S1, string S2)
{
if (S1.length() != S2.length()) {
return false ;
}
int n = S1.length();
if (n == 0) {
return true ;
}
if (S1 == S2) {
return true ;
}
string copy_S1 = S1, copy_S2 = S2;
sort(copy_S1.begin(), copy_S1.end());
sort(copy_S2.begin(), copy_S2.end());
if (copy_S1 != copy_S2) {
return false ;
}
string key = (S1 + " " + S2);
if (mp.find(key) != mp.end()) {
return mp[key];
}
bool flag = false ;
for ( int i = 1; i < n; i++) {
if (isScramble(S1.substr(0, i), S2.substr(0, i))
&& isScramble(S1.substr(i, n - i),
S2.substr(i, n - i))) {
flag = true ;
return true ;
}
if (isScramble(S1.substr(0, i), S2.substr(n - i, i))
&& isScramble(S1.substr(i, n - i),
S2.substr(0, n - i))) {
flag = true ;
return true ;
}
}
mp[key] = flag;
return false ;
}
int main()
{
string S1 = "coder" ;
string S2 = "ocred" ;
if (isScramble(S1, S2)) {
cout << "Yes" ;
}
else {
cout << "No" ;
}
return 0;
}
|
Java
import java.util.*;
public class Main
{
static HashMap<String, Boolean> mp = new HashMap<String, Boolean>();
static boolean isScramble(String S1, String S2)
{
if (S1.length() != S2.length()) {
return false ;
}
int n = S1.length();
if (n == 0 ) {
return true ;
}
if (S1.equals(S2)) {
return true ;
}
String copy_S1 = S1, copy_S2 = S2;
char [] t1 = copy_S1.toCharArray();
char [] t2 = copy_S2.toCharArray();
Arrays.sort(t1);
Arrays.sort(t2);
copy_S1 = new String(t1);
copy_S2 = new String(t2);
if (!copy_S1.equals(copy_S2)) {
return false ;
}
String key = (S1 + " " + S2);
if (mp.containsKey(key)) {
return mp.get(key);
}
boolean flag = false ;
for ( int i = 1 ; i < n; i++) {
if (isScramble(S1.substring( 0 , i), S2.substring( 0 , i))
&& isScramble(S1.substring(i, n), S2.substring(i, n))) {
flag = true ;
mp.put(key, flag);
return true ;
}
if (isScramble(S1.substring( 0 , i), S2.substring(n - i, n))
&& isScramble(S1.substring(i, n),
S2.substring( 0 , n - i))) {
flag = true ;
mp.put(key, flag);
return true ;
}
}
mp.put(key, flag);
return false ;
}
public static void main(String[] args) {
String S1 = "coder" ;
String S2 = "ocred" ;
if (isScramble(S1, S2)) {
System.out.print( "Yes" );
}
else {
System.out.print( "No" );
}
}
}
|
Python3
map = {}
def isScramble(S1: str , S2: str ):
if len (S1) ! = len (S2):
return False
n = len (S1)
if not n:
return True
if S1 = = S2:
return True
if sorted (S1) ! = sorted (S2):
return False
if (S1 + ' ' + S2 in map ):
return map [S1 + ' ' + S2]
flag = False
for i in range ( 1 , n):
if (isScramble(S1[:i], S2[:i]) and
isScramble(S1[i:], S2[i:])):
flag = True
return True
if (isScramble(S1[ - i:], S2[:i]) and
isScramble(S1[: - i], S2[i:])):
flag = True
return True
map [S1 + " " + S2] = flag
return False
if __name__ = = "__main__" :
S1 = "great"
S2 = "rgate"
if (isScramble(S1, S2)):
print ( "Yes" )
else :
print ( "No" )
|
C#
using System;
using System.Collections.Generic;
class GFG {
static Dictionary< string , bool > mp = new Dictionary< string , bool >();
static bool isScramble( string S1, string S2)
{
if (S1.Length != S2.Length) {
return false ;
}
int n = S1.Length;
if (n == 0) {
return true ;
}
if (S1 == S2) {
return true ;
}
string copy_S1 = S1, copy_S2 = S2;
char [] t1 = copy_S1.ToCharArray();
char [] t2 = copy_S2.ToCharArray();
Array.Sort(t1);
Array.Sort(t2);
copy_S1 = new string (t1);
copy_S2 = new string (t2);
if (copy_S1 != copy_S2) {
return false ;
}
string key = (S1 + " " + S2);
if (mp.ContainsKey(key)) {
return mp[key];
}
bool flag = false ;
for ( int i = 1; i < n; i++) {
if (isScramble(S1.Substring(0, i), S2.Substring(0, i))
&& isScramble(S1.Substring(i, n - i), S2.Substring(i, n - i))) {
flag = true ;
return true ;
}
if (isScramble(S1.Substring(0, i), S2.Substring(n - i, i))
&& isScramble(S1.Substring(i, n - i),
S2.Substring(0, n - i))) {
flag = true ;
return true ;
}
}
mp[key] = flag;
return false ;
}
static void Main() {
string S1 = "coder" ;
string S2 = "ocred" ;
if (isScramble(S1, S2)) {
Console.Write( "Yes" );
}
else {
Console.Write( "No" );
}
}
}
|
Javascript
<script>
let mp = new Map();
function isScramble(S1, S2)
{
if (S1.length != S2.length) {
return false ;
}
let n = S1.length;
if (n == 0) {
return true ;
}
if (S1 == S2) {
return true ;
}
let copy_S1 = S1, copy_S2 = S2;
let t1 = copy_S1.split(' ')
let t2 = copy_S2.split(' ')
t1.sort();
t2.sort();
copy_S1 = t1.join("");
copy_S2 = t2.join("");
if (copy_S1 != copy_S2) {
return false;
}
// make key of type string for search in map
let key = (S1 + " " + S2);
// checking if both string are before calculated or not
// if calculated means find in map then return it' s
if (mp.has(key)) {
return mp[key];
}
let flag = false ;
for (let i = 1; i < n; i++) {
if (isScramble(S1.substring(0, i), S2.substring(0, i))
&& isScramble(S1.substring(i, n),
S2.substring(i, n))) {
flag = true ;
return true ;
}
if (isScramble(S1.substring(0, i), S2.substring(n - i, n))
&& isScramble(S1.substring(i, n),
S2.substring(0, n - i))) {
flag = true ;
return true ;
}
}
mp[key] = flag;
return false ;
}
let S1 = "coder" ;
let S2 = "ocred" ;
if (isScramble(S1, S2)) {
document.write( "Yes" );
}
else {
document.write( "No" );
}
</script>
|
Time Complexity: O(N^2), where N is the length of the given strings.
Auxiliary Space: O(N^2), As we need to store O(N^2) string in our mp map.
Last Updated :
08 Feb, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...