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: true
Example 2:
Input: s1 = "abcde", s2 = "caebd" Output: false题源: here;完整实现: here
思路:
三种方案:1 递归法;2 动态规划;3 基于记忆的递归。
这三种方法都基于一条更新规则:
f[n][i][j]} = (f[k][i][j] && f[n-k][i+k][j+k])
|| (f[k][i][j+n-k] && f[n-k][i+k][j])
n表示字符串长度,i表示s1的起始位置,j表示s2的起始位置。
1 递归
bool recurse(string s1, int start1, int len, string s2, int start2){
if (len == 1) return s1[start1] == s2[start2];
for (int i = 1; i < len; i++){
if ((recurse(s1, start1, i, s2, start2) && recurse(s1, start1 + i, len - i, s2, start2 + i)) ||
(recurse(s1, start1, i, s2, start2 + len - i) && recurse(s1, start1 + i, len - i, s2, start2))
){
return true;
}
}
return false;
}
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size()) return false;
return recurse(s1, 0, s1.size(), s2, 0);
}
2 动态规划
bool isScramble2(string s1, string s2){
if (s1 == s2) return true;
if (s1.size() != s2.size()) return false;
vector<vector<vector<bool>>> dp(s1.size() + 1, vector<vector<bool>>(s1.size(), vector<bool>(s1.size(), false)));
for (int i = 0; i < s1.size(); i++){
for (int j = 0; j < s1.size(); j++){
dp[1][i][j] = s1[i] == s2[j];
}
}
for (int len = 2; len <= s1.size(); len++){
for (int i = 0; i < s1.size() - len + 1; i++){
for (int j = 0; j < s1.size() - len + 1; j++){
for (int subLen = 1; subLen < len && !dp[len][i][j]; subLen++){
dp[len][i][j] = (dp[subLen][i][j] && dp[len - subLen][i + subLen][j + subLen]) ||
(dp[subLen][i][j + len - subLen] && dp[len - subLen][i + subLen][j]);
}
}
}
}
return dp[s1.size()][0][0];
}
3 基于记忆的递归
bool recurse2(string s1, int start1, int len, string s2, int start2, vector<vector<vector<int>>>& memo){
if (memo[len][start1][start2] != -1) return memo[len][start1][start2];
if (len == 1){
memo[len][start1][start2] = s1[start1] == s2[start2] ? 1 : 0;
return memo[len][start1][start2];
}
for (int i = 1; i < len; i++){
if ((recurse2(s1, start1, i, s2, start2, memo) && recurse2(s1, start1 + i, len - i, s2, start2 + i, memo)) ||
(recurse2(s1, start1, i, s2, start2 + len - i, memo) && recurse2(s1, start1 + i, len - i, s2, start2, memo))
){
return memo[len][start1][start2] = 1;
}
}
return memo[len][start1][start2] = 0;
}
bool isScramble3(string s1, string s2){
if (s1 == s2) return true;
if (s1.size() != s2.size()) return false;
vector<vector<vector<int>>> memo(s1.size() + 1, vector<vector<int>>(s1.size(), vector<int>(s1.size(), -1)));
return recurse2(s1, 0, s1.size(), s2, 0, memo);
}