这道题被列为困难,确实难度大。我起初根本没想到能用动态规划解决,但是递归还是比较好理解的。
方法一:递归
借的一张图片
情况一表示不交换顺序,看s1是否等于t1&&s2是否等于t2
情况二表示交换顺序,看之前的s1是否等于s2&&s2是否等于s1(图中没有按照之前的标出,那就靠颜色区分吧)
然后不断递归即可
注意:
- 如果不剪枝,会超时
- 剪枝:1. 如果字符串为一个字符,直接判断即可
2. 可以通过map统计字符个数来判断
代码
class Solution {
public:
map<string,bool> M;
bool isScramble(string s1, string s2) {
if(s1.length()==1&&s1==s2){
return true;
}
map<char,int> M;
for(int i=0;i<s1.length();i++){
M[s1[i]]++;
M[s2[i]]--;
}
for(int i=0;i<s1.length();i++){
if(M[s1[i]]!=0){
return false;
}
}
for(int i=1;i<s1.length();i++){
if(isScramble(s1.substr(0,i),s2.substr(0,i))&&
isScramble(s1.substr(i),s2.substr(i))){
return true;
}
if(isScramble(s1.substr(i),s2.substr(0,s1.length()-i))
&&isScramble(s1.substr(0,i),s2.substr(s2.length()-i))){
return true;
}
}
return false;
}
};
方法二:动态规划
初始想法
dp[i][j][k][h] 表示 T[k…h] 是否由 S[i…j] 变来。由于变换必须长度是一样的,因此这边有个关系 j - i = h - k ,可以把四维数组降成三维。dp[i][j][len] 表示从字符串 S 中 i开始长度为 len 的字符串是否能变换为从字符串 T 中 j 开始长度为 len 的字符串
转移方程
dp[i][j][len]=dp[i][j][k]&&dp[i+k][j+k][p-k] (第一种情况)
dp[i][j][len]=dp[i][j+p-k][k]&&dp[i+k][j][p-k](第二种情况)
初始化:
需要对dp[i][j][1]逐一赋值,作为状态转移方程的初始条件
class Solution {
public:
bool isScramble(string s1, string s2) {
if(s1.length()==1&&s1==s2){
return true;
}
map<char,int> M;
for(int i=0;i<s1.length();i++){
M[s1[i]]++;
M[s2[i]]--;
}
for(int i=0;i<s1.length();i++){
if(M[s1[i]]!=0){
return false;
}
}
int len=s1.length();
int dp[len][len][len+1];
memset(dp,false,sizeof(dp));
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
if(s1[i]==s2[j]){
dp[i][j][1]=true;
}
}
}
for(int p=2;p<=len;p++){
for(int i=0;i+p<=len;i++){
for(int j=0;j+p<=len;j++){
for(int k=1;k<p;k++){
if(dp[i][j][k]&&dp[i+k][j+k][p-k]){
dp[i][j][p]=true;
break;
}
if(dp[i][j+p-k][k]&&dp[i+k][j][p-k]){
dp[i][j][p]=true;
break;
}
}
}
}
}
return dp[0][0][len];
}
};