Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
前言
力扣第131题 分割回文串 如下所示:
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。
回文串 是正着读和反着读都一样的字符串。
示例 1:
输入: s = "aab"
输出: [["a","a","b"],["aa","b"]]
示例 2:
输入: s = "a"
输出: [["a"]]
一、思路
题目的意思很明确,就是将字符串 s 分割为很多子串,保证每个子串都是 回文串。返回 s 所有可能的分割方案。
题目的难点就在于如何确定分割字符串的位置呢?一个朴素的想法就是:通过递归来逐个分解字符,但是这样需要对每次分割出来的子串都要判定是否为 回文串,只有在碰到子串为回文串的情况下,才会继续向下一层递归。
可以发现我们递归钟最难的就是需寻找下一个回文子串在什么位置,以确定如何分割字符串 s。其实要想知道某个位置 i ~ j 是否为回文串?这个问题就是经典的 动态规划题目 了。可以使用 动态规划 很轻松来确定所有回文子串的位置。
动态规划的本质就是将大问题化解为小问题,从而大大降低时间复杂度。在这一题使用动态规划的时候要注意填表格的顺序:从下往上
综上所述,这一题的大致步骤如下:
- 使用
动态规划确定i~j是否为回文串( -1< i =< j < len) - 使用
递归深度遍历字符串s,在分割到字符串最后一位时收集结果即可
递归时为了避免回头,我们用
current表示当前分割的起始位置,初始值为0
二、实现
实现代码
实现代码与思路中完全保持一致
boolean[][] flag;
List<List<String>> ret = new ArrayList<>();
public List<List<String>> partition(String s) {
int len = s.length();
flag = new boolean[len][len];
for (int i = len - 1; i >= 0; i--)
{
for (int j = i; j < len; ++j)
{
if (i == j) // 对角线
flag[i][j] = true;
else if (j == i + 1)
flag[i][j] = s.charAt(i) == s.charAt(j);
else
flag[i][j] = s.charAt(i) == s.charAt(j) && flag[i + 1][j - 1];//s[i]是否等于s[j] && 小区间是否为回文串
}
}
dfs(s, 0, new Stack<>());
return ret;
}
public void dfs(String s, int current, Stack<String> tempRet) {
int len = s.length();
if (current == len) {
// 收集结果
ret.add(new ArrayList<>(tempRet));
return;
}
for (int j = current; j < len; ++j) {
if (flag[current][j]) {
tempRet.push(s.substring(current, j + 1));
dfs(s, j + 1, tempRet);
tempRet.pop();
}
}
}
测试代码
public static void main(String[] args) {
String str = "aab";
new Number131().partition(str);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~