一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
1.题目一
131. 分割回文串
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]] 示例 2:
输入:s = "a" 输出:[["a"]]
思路
回溯法三部曲
- 递归函数的返回值以及参数
- 回溯函数终止条件
- 单层搜索的过程 还是那句话画图能更清晰了解,此处我就不画图了。
与前几个不同,此处是分割字符串并不是选择,所以我们来看看到底咋写
题意问的是,切分字符串s,切出的每一个子串必须是回文串,请找出所有切分的可能。
我们用指针 start 试着去切,切出一个回文串,基于新的 start,继续往下切,直到 start 越界
每次基于当前的 start,可以选择不同的 i,切出 start 到 i 的子串,我们枚举出这些选项 i:
切出的子串满足回文,将它加入部分解 temp 数组,并继续往下切(递归) 切出的子串不是回文,跳过该选择,不落入递归,继续下一轮迭代
为什么要回溯 因为不是找到一个合法的部分解就完事,要找齐所有的合法的部分解。
下面两种情况,是结束当前递归的两种情形:
1.指针越界了,没有可以切分的子串了,递归到这一步,说明一直在切出回文串,现在生成了一个合法的部分解,return
2.走完了当前递归的 for 循环,考察了基于当前 start 的所有的切分可能,当前递归自然地结束 它们都代表,当前作出的选择,所进入的递归,结束了,该分支的搜索结束了,该去搜另一分支了
所以当前递归结束后,要将当前的选择撤销,回到选择前的状态,去考察另一个选择,即进入下一轮迭代,尝试另一种切分的可能。
这样才能在解的空间树中,把路走全了,搜出所有的合法部分解。
代码
var partition = function (s) {
const res = [];
function dfs(temp, start) {
if (start == s.length) {
res.push(temp.slice());
return;
}
for (let i = start; i < s.length; i++) {
if (isPali(s, start, i)) {
//substring(start,end) === slice(start,end)
// substr(start, length)
temp.push(s.substring(start, i + 1));
dfs(temp, i + 1);
temp.pop();
}
}
}
dfs([], 0);
return res;
};
function isPali(s, l, r) {
while (l < r) {
if (s[l] != s[r]) {
return false;
}
l++;
r--;
}
return true;
}