1、题目描述
给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树。
下图是字符串 s1 = "great"
的一种可能的表示形式。
在扰乱这个字符串的过程中,我们可以挑选任何一个非叶节点,然后交换它的两个子节点。
例如,如果我们挑选非叶节点 "gr" ,交换它的两个子节点,将会产生扰乱字符串 "rgeat" 。我们将 "rgeat”
称作 "great"
的一个扰乱字符串。
2、示例
输入: s1 = "great", s2 = "rgeat"
输出: true
输入: s1 = "abcde", s2 = "caebd"
输出: false
3、题解
基本思想:递归法,遍历所有可能的分割情况分割点i从1到s1.size-1,将s1分割成[0,i)[i,s1.size),对应s2匹配可能是[0,i)[i,s1.size)也可能是[s2.size-i,s2.size)[0,s2.size()-i),然后不断递归分割的子串直到s1=s2返回true。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
unordered_map<string,unordered_map<string,int>> Map; //Map[s1][s2]=1表示s1和s2匹配,Map[s1][s2]=-1表示s1和s2不匹配,Map[s1][s2]=0表示s1和s2还没有递归搜索
bool isScramble(string s1, string s2) {
return Recursion(s1, s2);
}
bool Recursion(string s1, string s2)
{
if (s1 == s2)
{
Map[s1][s2]=1;
return true;
}
//防止超时,若s1中所有字符在s2中不都存在,说明s1无论怎么分割和s2无法匹配,直接返回false,大大优化效率
string t1 = s1, t2 = s2;
sort(t1.begin(), t1.end());
sort(t2.begin(), t2.end());
if (t1 != t2)
{
Map[s1][s2]=-1;
return false;
}
//i从1到s1.size-1,不能从下标0开始,至少分割1个字符出来,否则无法跳出循环
for (int i = 1; i < s1.size(); i++)
{
//将s1分割成s1l=[0,i)s1r=[i,s1.size)对应s2匹配可能是s2l=[0,i)s2r=[i,s1.size)也可能是s3l=[s2.size-i,s2.size)s3r=[0,s2.size()-i)
string s1l=s1.substr(0, i),s1r=s1.substr(i,s1.size()-i);
string s2l=s2.substr(0, i),s2r=s2.substr(i,s2.size()-i);
string s3l=s2.substr(s2.size() - i, i),s3r=s2.substr(0, s2.size() - i);
bool flag11,flag12,flag21,flag22,flag1,flag2;
if(Map[s1l][s2l]==1)
flag11=true;
else if(Map[s1l][s2l]==-1)
flag11=false;
else
flag11=Recursion(s1l, s2l);
if(Map[s1r][s2r]==1)
flag12=true;
else if(Map[s1r][s2r]==-1)
flag12=false;
else
flag12=Recursion(s1r, s2r);
flag1=flag11&&flag12;
if(flag1)
{
Map[s1][s2]=1;
return true;
}
if(Map[s1l][s3l]==1)
flag21=true;
else if(Map[s1l][s3l]==-1)
flag21=false;
else
flag21=Recursion(s1l, s3l);
if(Map[s1r][s3r]==1)
flag22=true;
else if(Map[s1r][s3r]==-1)
flag22=false;
else
flag22=Recursion(s1r, s3r);
flag2=flag21&&flag22;
if (flag2)
{
Map[s1][s2]=1;
return true;
}
}
Map[s1][s2]=-1;
return false;
}
};
class Solution {
public:
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size())
return false;
//基本思想:递归法,遍历所有可能的分割情况分割点i从1到s1.size-1,将s1分割成[0,i)[i,s1.size)
//对应s2匹配可能是[0,i)[i,s1.size)也可能是[s2.size-i,s2.size)[0,s2.size()-i)
//然后不断递归分割的子串直到s1=s2返回true
return Recursion(s1, s2);
}
bool Recursion(string s1, string s2)
{
if (s1 == s2)
return true;
//防止超时,若s1中所有字符在s2中不都存在,说明s1无论怎么分割和s2无法匹配,直接返回false,大大优化效率
string t1 = s1, t2 = s2;
sort(t1.begin(), t1.end());
sort(t2.begin(), t2.end());
if (t1 != t2)
return false;
//i从1到s1.size-1,不能从下标0开始,至少分割1个字符出来,否则无法跳出循环
for (int i = 1; i < s1.size(); i++)
{
//将s1分割成[0,i)[i,s1.size)对应s2匹配可能是[0,i)[i,s1.size)也可能是[s2.size-i,s2.size)[0,s2.size()-i)
bool flag1 = Recursion(s1.substr(0, i), s2.substr(0, i)) && Recursion(s1.substr(i,s1.size()-i), s2.substr(i,s2.size()-i));
bool flag2 = Recursion(s1.substr(0, i), s2.substr(s2.size() - i, i)) && Recursion(s1.substr(i, s1.size() - i), s2.substr(0, s2.size() - i));
if (flag1 || flag2)
return true;
}
return false;
}
};
int main()
{
Solution solute;
string s1 = "abcd";
string s2 = "cadb";
cout << solute.isScramble(s1, s2) << endl;
return 0;
}