持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
前言
今天的题目为中等,题目本身也是回溯组合类型的问题,只不过要求有点不同,但是整个的一个思路和前几天的组合回溯是完全相同的。
每日一题
今天的题目是 131. 分割回文串,难度都为中等。
-
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
-
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a"
输出:[["a"]]
提示:
- 1 <= s.length <= 16
- s 仅由小写英文字母组成
题解
往期回溯练习题
组合回溯1 leetcode刷题记录-77. 组合(回溯基础)
组合回溯2 leetcode刷题记录-216. 组合总和 III(回溯剪枝)
组合回溯3 leetcode刷题记录-17. 电话号码的字母组合(回溯组合问题)
组合回溯4 leetcode刷题记录-回溯之组合总和 1&2
回溯
本题也算是组合类型的回溯问题,因为字符串的切割,其实就是分为在字符串的某个位置进行切割,比如说,a,a,b 切割为 a | a | b 那就相当于选取 a,a,b 三个元素,如果切割为 aa | b 那就相当于选取了 第二个 a 以及最后的 b 元素,这样看来的话,是不是和组合问题有着异曲同工之妙,要是还是不是很清楚,我们可以用 a,a,b 这个例子来进行每一项分隔,看一下分隔的流程图是怎么样的。
从上图中就能够更加直观的感受到,其实去字符串的所有分隔方式,跟选字符串的所有组合,是同样的一个流程。
那么既然在叶子节点我们能够拿到当前的一个切割结果,那么是不是就可以简单的拿着这个接过去计算是不是满足题目要求的回文子串。
然后我们在写一个简单的小函数,用于判断当前传入的字符串是否为回文子串,利用双指针从字符串的头尾往中间挪动一直对比就可以了。
function partition(s: string): string[][] {
let res = []
let path = []
const backtracking = (index) => {
if (index >= s.length) {
res.push([...path])
return
}
for (let i = index; i < s.length; i++) {
let sChildren = s.slice(index, i+1)
if (isPalindrome(sChildren)) {
path.push(sChildren)
} else {
continue
}
backtracking(i + 1)
path.pop()
}
}
backtracking(0)
return res
};
function isPalindrome(s: string) {
for (let i = 0, j = s.length-1; i < j; i++, j--) {
if(s[i] !== s[j]) return false;
}
return true;
}