两个字符串满足什么条件才称得上是scramble的呢?
如果s1和s2的长度等于1,显然只有s1=s2时才是scramble关系。
如果s1和s2的长度大于1,那么就对s1和s2进行分割,划分成两个子问题分别处理。
如何分割呢?当然不能任意分割。假设分割后s1变成了s11和s12,s2变成了s21和s22,那么只有2种分割方式:
1. s11.length = s21.length & s12.length = s22.length,如下图所示:
s1: ? ? ? ? ?
----- ---
s11 s12 s2: ? ? ? ? ?
----- ---
s21 s22
2. s11.length = s22.length & s12.length = s21.length,如下图所示:
s1: ? ? ? ? ?
----- ---
s11 s12 s2: ? ? ? ? ?
--- -----
s21 s22
经过分割后,我们可以得到长度相等的两组子串,正好是两个子问题。于是就可以递归分割下去了,直到两个串的长度长度为1停止分割。
令scramblep[i][j][k]表示s1[i..i+k]和s2[j..j+k]相互之间是否是scramble关系,即i是s1的子串起始位置,j是s2的子串起始位置,k是子串的长度。则有如下递推公式:
scramblep[i][j][k] = (scramblep[i][j][t] && scramblep[i+t][j+t][k-t]) || (scramblep[i][j+k-t][t] && scramblep[i+t][j][k-t]),其中0 < t < k
(正好对应上面说的两种分割方式)
初值为:scramblep[i][j][k] = s1[i..i+k] == s2[j..j+k],(如果两个子串相等,自然是scramble关系。这个初值包含了长度为1的情况)
代码:
bool isScramble(string s1, string s2) {
if (s1.length() != s2.length()) return false;
if (s1.empty()) return true; int len = s1.length();
bool ***judge = new bool**[len];
for (int i = ; i < len; i++) {
judge[i] = new bool*[len];
for (int j = ; j < len; j++)
judge[i][j] = new bool[len + ];
} for (int k = ; k <= len; k++) {
for (int i = ; i + k <= len; i++) {
for (int j = ; j + k <= len; j++) {
judge[i][j][k] = s1.substr(i, k) == s2.substr(j, k);
for (int t = ; t < k && !judge[i][j][k]; t++) {
judge[i][j][k] |= judge[i][j + k - t][t] && judge[i + t][j][k - t];
judge[i][j][k] |= judge[i][j][t] && judge[i + t][j + t][k - t];
}
}
}
} return judge[][][len];
}
new出来的内存都没有delete,面试的时候别忘了啊。