题目描述:使用下面描述的算法可以扰乱字符串 s 得到字符串 t :
如果字符串的长度为 1 ,算法停止
如果字符串的长度 > 1 ,执行下述步骤:
在一个随机下标处将字符串分割成两个非空的子字符串。即,如果已知字符串 s ,则可以将其分成两个子字符串 x 和 y ,且满足 s = x + y 。
随机 决定是要「交换两个子字符串」还是要「保持这两个子字符串的顺序不变」。即,在执行这一步骤之后,s 可能是 s = x + y 或者 s = y + x 。
在 x 和 y 这两个子字符串上继续从步骤 1 开始递归执行此算法。
给你两个 长度相等 的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。如果是,返回 true ;否则,返回 false 。
示例如下:
输入:s1 = “great”, s2 = “rgeat”
输出:true
解使:其实我不想放解释了,我看不懂解释
然后呢,这个题主要是动态规划里面一个问题,可以用区间dp来解决。
区间dp就是建立在区间搜索上的动态规划。其实是有一个模板的,大概是以下几步
//初始化dp数组
//枚举区间长度
//枚举起始点
//枚举终点
//枚举分割点
如这个题中,需要分割为两个字符串,步骤可为以下
//枚举区间长度
for (len=2;len<=Length_1;len++){
//枚举第一个字符串起点
for (i=0;i<=Length_1-len;i++){
//枚举第二个字符串起点
for (j=0;j<=Length_1-len;j++){
//枚举分割点
for (k=1;k<=len-1;k++){
//balabala
}
}
}
}
动态规划最重要的就是状态方程,这里有两个情况
如s1_left | s1_right
和s2_left | s2_right
- 分割完以后,不交换位置。即
s1_left对应s2_left
。 - 交换位置,即
s1_left对应s2_right
。
这里可以设置一个数组dp[i][j][t][k]
,用来表示s1[i:j]和s2[t:k]
是否匹配。
因为区间长度肯定一样,所以可以再化简一下,变成dp[i][j][k]
,即s1和s2的起点分别为i和j,区间长度为k。
然后状态方程的话,如下判断
//情况1
dp[i][j][k]==1 && dp[i+k][j+k][len-k]==1
//情况2
dp[i][j+len-k][k]==1 && dp[i+k][j][len-k]==1
在判断赋值的时候都用k在每个小区间进行遍历,即先用len划分一个一个大区间,在每个区间里用k划分两个小区间,判断是否匹配。
然后dp[0][0][len]
就是最终结果了。
然后还要对初始空间初始化,当区间为1的时候,所有都匹配。
for (i=0;i<Length_1;i++){
for (j=0;j<Length_1;j++){
if (s1.charAt(i)==s2.charAt(j))
dp[i][j][1]=1;
else
dp[i][j][1]=-1;
}
}
完整代码
static boolean isScramble(String s1, String s2) {
int Length_1=s1.length(),Length_2=s2.length();
if (Length_1!=Length_2)
return false;
int[][][] dp=new int[Length_1][Length_1][Length_1+1];
int i=0,j=0,len=0,k=0;
for (i=0;i<Length_1;i++){
for (j=0;j<Length_1;j++){
if (s1.charAt(i)==s2.charAt(j))
dp[i][j][1]=1;
else
dp[i][j][1]=-1;
}
}
//kaishi
for (len=2;len<=Length_1;len++){
for (i=0;i<=Length_1-len;i++){
for (j=0;j<=Length_1-len;j++){
for (k=1;k<=len-1;k++){
if (dp[i][j][k]==1 && dp[i+k][j+k][len-k]==1)
dp[i][j][len]=1;
if (dp[i][j+len-k][k]==1 && dp[i+k][j][len-k]==1)
dp[i][j][len]=1;
}
}
}
}
return dp[0][0][Length_1]==1;
}