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.
In the beginning, I wanna enumerate all scramble strings of s1. However, the recursive program wastes too much memory. Meanwhile, the partition is not limited to the mid. The right solution is to consider both s1 and s2 at the same time. The following is the code:
class Solution {
public:
bool isScramble(string s1, string s2) {
// Note: The Solution object is instantiated only once and is reused by each test case.
if (s1 == s2)
return true;
if (s1.length() != s2.length())
return false;
int v1 = 0, v2 = 0, i, j;
for (i = 0; i < s1.length(); ++i)
v1 += s1[i] - 'a';
for (i = 0; i < s2.length(); ++i)
v2 += s2[i] - 'a';
if (v1 != v2)
return false;
int len = s1.length();
for (i = 1; i < len; ++i) {
if (isScramble(s1.substr(0,i), s2.substr(0,i)) && isScramble(s1.substr(i), s2.substr(i)))
return true;
if (isScramble(s1.substr(0,i), s2.substr(len - i, i)) && isScramble(s1.substr(i), s2.substr(0, len - i)))
return true;
}
}
};
Python Version:
class Solution:
def isSumTotal(self, s1, s2, l):
sum1, sum2 = 0, 0
for i in range(l):
sum1 += ord(s1[i]) - ord('a')
sum2 += ord(s2[i]) - ord('a')
return sum1 == sum2
def isScramble(self, s1, s2):
l1, l2 = len(s1), len(s2)
if (l1 != l2):
return False
if (self.isSumTotal(s1, s2, l1) == False):
return False
if (s1 == s2):
return True
for i in range(1, l1):
if (self.isScramble(s1[0:i], s2[0:i]) and self.isScramble(s1[i:], s2[i:])):
return True
if (self.isScramble(s1[0:i], s2[(l1-i):l1]) and self.isScramble(s1[i:l1],s2[0:(l1-i)])):
return True
return False
if __name__ == '__main__':
s = Solution()
print(s.isScramble("abc", "bca"))
Notice "abcd" and "bdac" are True, so the following codes are wrong:
class Solution:
def isValidOff(self, s1, s2, start, end, off):
return (s1[start:off] == s2[(end+1-(off-start)):(end+1)] and s1[off:(end+1)] == s2[start:(start+end-off+1)])
def isValid(self, s1, s2, start, end):
off = start+1
while (off <= end):
if (self.isValidOff(s1, s2, start, end, off)):
return True
off += 1
return False
def isTwoSideSame(self, s1, s2, l):
for leni in range(1, l-1):
for lenj in range(1, l-leni):
if (s1[0:leni] == s2[(l-leni):l] and s2[0:lenj] == s1[(l-lenj):l]):
return True
return False
def isSumTotal(self, s1, s2, l):
sum1, sum2 = 0, 0
for i in range(l):
sum1 += ord(s1[i]) - ord('a')
sum2 += ord(s2[i]) - ord('a')
return sum1 == sum2
def isScramble(self, s1, s2):
l1, l2 = len(s1), len(s2)
if (l1 != l2):
return False
start, end = 0, l1 - 1
while (start <= end):
if (s1[start] == s2[start]):
start += 1
else:
break
while (start <= end):
if (s1[end] == s2[end]):
end -= 1
else:
break
return True
if (start > end):
return True
else:
return self.isValid(s1, s2, start, end) or self.isTwoSideSame(s1[start:(end+1)], s2[start:(end+1)],end-start+1)
if __name__ == '__main__':
s = Solution()
print(s.isScramble("abc", "cba"))
print(s.isScramble("abc", "rgeat"))
print(s.isScramble("great", "rgeat"))
print(s.isScramble("abcde", "caebd"))