一、题目描述:
leetcode-cn.com/problems/sc…
使用下面描述的算法可以扰乱字符串 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 。
****示例 1:
输入:s1 = "great", s2 = "rgeat"
输出:true
解释:s1 上可能发生的一种情形是:
"great" --> "gr/eat" // 在一个随机下标处分割得到两个子字符串
"gr/eat" --> "gr/eat" // 随机决定:「保持这两个子字符串的顺序不变」
"gr/eat" --> "g/r / e/at" // 在子字符串上递归执行此算法。两个子字符串分别在随机下标处进行一轮分割
"g/r / e/at" --> "r/g / e/at" // 随机决定:第一组「交换两个子字符串」,第二组「保持这两个子字符串的顺序不变」
"r/g / e/at" --> "r/g / e/ a/t" // 继续递归执行此算法,将 "at" 分割得到 "a/t"
"r/g / e/ a/t" --> "r/g / e/ a/t" // 随机决定:「保持这两个子字符串的顺序不变」
算法终止,结果字符串和 s2 相同,都是 "rgeat"
这是一种能够扰乱 s1 得到 s2 的情形,可以认为 s2 是 s1 的扰乱字符串,返回 true
二、思路分析:
dfs + 记忆化搜索 + 剪枝
方法一:
- 直接找出s1所有的扰乱字符串,放在集合里,最后判断s2是否在集合中。
- 递归函数定义为返回字符串s的所有扰乱字串 方法二:
- 递归函数定义为s1与s2是否为扰乱字符串,切割字符串,然后递归的判断字串是否为扰乱字符串
- 循环字符串设置i为切割点,isScramble(s1,s2) = dfs(s1[0,i], s2[0,i]) && dfs(s1[i,n], s2[i,n]) || dfs(s1[0-i], s2[n-i,n]) && dfs(s1[i,n], s2[0,n-i])
三、AC 代码:
/**
* @param {string} s1
* @param {string} s2
* @return {boolean}
*/
var isScramble = function (s1, s2) {
const map = {}
function strDfs(str) {
const res = new Set()
if (!str) {
return res
}
if (str.length === 1) {
return res.add(str)
}
if (map[str] !== undefined) {
return map[str]
}
for (let i = 1; i < str.length; i++) {
const substr1 = str.substring(i)
const substr2 = str.substring(0, i)
const strs1Arr = strDfs(substr1)
const strs2Arr = strDfs(substr2)
strs2Arr.forEach(str1 => {
strs1Arr.forEach(str2 => {
const combineStr1 = str1 + str2
if (s2.indexOf(combineStr1) !== -1) {
res.add(combineStr1)
}
const combineStr2 = str2 + str1
if (s2.indexOf(combineStr2) !== -1) {
res.add(combineStr2)
}
})
})
}
map[str] = res
return res
}
return strDfs(s1).has(s2)
};
/**
* @param {string} s1
* @param {string} s2
* @return {boolean}
*/
var isScramble = function (s1, s2) {
const map = {}
function dfs(a, b) {
if (a.length !== b.length) {
return false
}
if (a.length === 1) {
return a === b
}
if(map[a+b]!==undefined){
return map[a+b]
}
for (let i = 1; i < a.length; i++) {
const subAstr1 = a.substring(0, i)
const subAstr2 = a.substring(i)
const subBstr1 = b.substring(0, i)
const subBstr2 = b.substring(i)
const subBstr3 = b.substring(0, a.length - i)
const subBstr4 = b.substring(a.length - i)
if (dfs(subAstr1, subBstr1) && dfs(subAstr2, subBstr2)) {
map[a+b] = true
return true
} else if (dfs(subAstr1, subBstr4) && dfs(subAstr2, subBstr3)) {
map[a+b] = true
return true
}
}
map[a+b] = false
return false
}
return dfs(s1, s2)
};