[LeetCode] Palindrome Partitioning 拆分回文串
Given a string s, partition s such that every substring of the partition is a palindrome.
Return all possible palindrome partitioning of s.
Example:
- Input: "aab"
- Output:
- [
- ["aa","b"],
- ["a","a","b"]
- ]
这又是一道需要用DFS来解的题目,既然题目要求找到所有可能拆分成回文数的情况,那么肯定是所有的情况都要遍历到,对于每一个子字符串都要分别判断一次是不是回文数,那么肯定有一个判断回文数的子函数,还需要一个DFS函数用来递归,再加上原本的这个函数,总共需要三个函数来求解。我们将已经检测好的回文子串放到字符串数组out中,当s遍历完了之后,将out加入结果res中。那么在递归函数中我们必须要知道当前遍历到的位置,用变量start来表示,所以在递归函数中,如果start等于字符串s的长度,说明已经遍历完成,将out加入结果res中,并返回。否则就从start处开始遍历,由于不知道该如何切割,所以我们要遍历所有的切割情况,即一个字符,两个字符,三个字符,等等。。首先判断取出的子串是否是回文串,调用一个判定回文串的子函数即可,这个子函数传入了子串的起始和终止的范围,若子串是回文串,那么我们将其加入out,并且调用递归函数,此时start传入 i+1,之后还要恢复out的状态。
那么,对原字符串的所有子字符串的访问顺序是什么呢,如果原字符串是 abcd, 那么访问顺序为: a -> b -> c -> d -> cd -> bc -> bcd-> ab -> abc -> abcd, 这是对于没有两个或两个以上子回文串的情况。那么假如原字符串是 aabc,那么访问顺序为:a -> a -> b -> c -> bc -> ab -> abc -> aa -> b -> c -> bc -> aab -> aabc,中间当检测到aa时候,发现是回文串,那么对于剩下的bc当做一个新串来检测,于是有 b -> c -> bc,这样扫描了所有情况,即可得出最终答案,代码如下:
解法一:
- class Solution {
- public:
- vector<vector<string>> partition(string s) {
- vector<vector<string>> res;
- vector<string> out;
- helper(s, , out, res);
- return res;
- }
- void helper(string s, int start, vector<string>& out, vector<vector<string>>& res) {
- if (start == s.size()) { res.push_back(out); return; }
- for (int i = start; i < s.size(); ++i) {
- if (!isPalindrome(s, start, i)) continue;
- out.push_back(s.substr(start, i - start + ));
- helper(s, i + , out, res);
- out.pop_back();
- }
- }
- bool isPalindrome(string s, int start, int end) {
- while (start < end) {
- if (s[start] != s[end]) return false;
- ++start; --end;
- }
- return true;
- }
- };
我们也可以不单独写递归函数,而是使用原函数本身来递归。首先判空,若字符串s为空,则返回一个包有空字符串数组的数组,注意这里不能直接返回一个空数组,后面会解释原因。然后我们从0开始遍历字符串s,因为是使用原函数当递归,所以无法传入起始位置start,所以只能从默认位置0开始,但是我们的输入字符串s是可以用子串来代替的,这样就相当于起始位置start的作用。首先我们还是判断子串是否为回文串,这里的判断子串还是得用一个子函数,由于起点一直是0,所以只需要传一个终点位置即可。如果子串是回文串,则对后面的整个部分调用递归函数,这样我们会得到一个二维数组,是当前子串之后的整个部分拆分为的回文串的所有情况,那么我们只需将当前的回文子串加入到返回的这些所有情况的集合中。现在解释下之前说的为啥当字符串s为空的时候,要返回一个带有空数组的数组,这是因为当子串就是原字符串s的时候,而是还是个回文串,那么后面部分就为空了,若我们对空串调用递归返回的是一个空数组,那么就无法对其进行遍历,则当前的回文串就无法加入到结果res之中,参见代码如下:
解法二:
- class Solution {
- public:
- vector<vector<string>> partition(string s) {
- vector<vector<string>> res;
- if (s.empty()) return {{}};
- for (int i = ; i < s.size(); ++i) {
- if (!isPalindrome(s, i + )) continue;
- for (auto list : partition(s.substr(i + ))) {
- list.insert(list.begin(), s.substr(, i + ));
- res.push_back(list);
- }
- }
- return res;
- }
- bool isPalindrome(string s, int n) {
- for (int i = ; i < n / ; ++i) {
- if (s[i] != s[n - - i]) return false;
- }
- return true;
- }
- };
下面这种解法是基于解法一的优化,我们可以先建立好字符串s的子串回文的dp数组,光这一部分就可以另出一个道题了 Palindromic Substrings,当我们建立好这样一个二维数组dp,其中 dp[i][j] 表示 [i, j] 范围内的子串是否为回文串,这样就不需要另外的子函数去判断子串是否为回文串了,大大的提高了计算的效率,岂不美哉?!递归函数的写法跟解法一中的没啥区别,可以看之前的讲解,参见代码如下:
解法三:
- class Solution {
- public:
- vector<vector<string>> partition(string s) {
- int n = s.size();
- vector<vector<string>> res;
- vector<string> out;
- vector<vector<bool>> dp(n, vector<bool>(n));
- for (int i = ; i < n; ++i) {
- for (int j = ; j <= i; ++j) {
- if (s[i] == s[j] && (i - j <= || dp[j + ][i - ])) {
- dp[j][i] = true;
- }
- }
- }
- helper(s, , dp, out, res);
- return res;
- }
- void helper(string s, int start, vector<vector<bool>>& dp, vector<string>& out, vector<vector<string>>& res) {
- if (start == s.size()) { res.push_back(out); return; }
- for (int i = start; i < s.size(); ++i) {
- if (!dp[start][i]) continue;
- out.push_back(s.substr(start, i - start + ));
- helper(s, i + , dp, out, res);
- out.pop_back();
- }
- }
- };
再来看一种迭代的解法,这里还是像上个解法一样建立判断字符串s的子串是否为回文串的dp数组,但建立了一个三维数组的res,这里的res数组其实也可以看作是一个dp数组,其中 res[i] 表示前i个字符组成的子串,即范围 [0, i+1] 内的子串的所有拆分方法,那么最终只要返回 res[n] 极为所求。然后进行for循环,i 从 0 到 n,j 从 0 到 i,这里我们同时更新了两个dp数组,一个是回文串的dp数组,另一个就是结果res数组了,对于区间 [j, i] 的子串,若其是回文串,则 dp[j][i] 更新为 true,并且遍历 res[j] 中的每一种组合,将当前子串加入,并且存入到 res[i+1] 中,参见代码如下:
解法四:
- class Solution {
- public:
- vector<vector<string>> partition(string s) {
- int n = s.size();
- vector<vector<vector<string>>> res(n + );
- res[].push_back({});
- vector<vector<bool>> dp(n, vector<bool>(n));
- for (int i = ; i < n; ++i) {
- for (int j = ; j <= i; ++j) {
- if (s[i] == s[j] && (i - j <= || dp[j + ][i - ])) {
- dp[j][i] = true;
- string cur = s.substr(j, i - j + );
- for (auto list : res[j]) {
- list.push_back(cur);
- res[i + ].push_back(list);
- }
- }
- }
- }
- return res[n];
- }
- };
类似题目:
参考资料:
https://leetcode.com/problems/palindrome-partitioning/
https://leetcode.com/problems/palindrome-partitioning/discuss/41982/Java-DP-%2B-DFS-solution
https://leetcode.com/problems/palindrome-partitioning/discuss/41963/Java%3A-Backtracking-solution.
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Palindrome Partitioning 拆分回文串的更多相关文章
- 131 Palindrome Partitioning 分割回文串
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串.返回 s 所有可能的分割方案.例如,给出 s = "aab",返回[ ["aa"," ...
- lintcode:Palindrome Partitioning 分割回文串
题目: 分割回文串 给定一个字符串s,将s分割成一些子串,使每个子串都是回文串. 返回s所有可能的回文串分割方案. 样例 给出 s = "aab",返回 [ ["aa&q ...
- Leetcode131. Palindrome Partitioning分割回文串
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. 示例: 输入: "aab" 输出: [ ["aa",&quo ...
- [LeetCode] Palindrome Partitioning II 拆分回文串之二
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...
- [LeetCode] Longest Palindrome 最长回文串
Given a string which consists of lowercase or uppercase letters, find the length of the longest pali ...
- [LeetCode] Palindrome Linked List 回文链表
Given a singly linked list, determine if it is a palindrome. Follow up: Could you do it in O(n) time ...
- [LeetCode] Palindrome Permutation II 回文全排列之二
Given a string s, return all the palindromic permutations (without duplicates) of it. Return an empt ...
- [Leetcode] palindrome partition ii 回文分区
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...
- Palindrome Partitioning (回文子串题)
Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...
随机推荐
- ASP.NET Core 中文文档 第三章 原理(5)错误处理
原文:Error Handling 作者:Steve Smith 翻译:谢炀(Kiler) 校对:高嵩(jack2gs).何镇汐 当你的ASP.NET应用发生错误的时候, 你可以采用本文所述的各种方法 ...
- 在项目中同时使用Objective-C和Swift
苹果发布的Swift语言可以和之前的Objective-C语言同时存在于一个项目中. 可能有人会认为是同一个类文件中既可以有Objective-C也可以有Swift,这是不对的.同一个类文件或同一个代 ...
- 通过pycharm使用git[图文详解]
前言 使用git+pycharm有一段时间了,算是稍有点心得,这边整理一下,可能有的方法不是最优,欢迎交流,可能还是习惯敲命令去使用git,不过其实pycharm已经帮忙做了很多了,我们可以不用记住那 ...
- react初始(1)
前言:react框架的出现是因为Facebook在建设Instagram交流平台的时候要处理大量的数据流,但是行业流行的MVC框架并不能适合Facebook公司的要求,他们就组织了自己的人力来开发re ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- 手把手教从零开始在GitHub上使用Hexo搭建博客教程(一)-附GitHub注册及配置
前言 有朋友问了我关于博客系统搭建相关的问题,由于是做开发相关的工作,我给他推荐的是使用github的gh-pages服务搭建个人博客. 推荐理由: 免费:github提供gh-pages服务是免费的 ...
- Web API项目中使用Area对业务进行分类管理
在之前开发的很多Web API项目中,为了方便以及快速开发,往往把整个Web API的控制器放在基目录的Controllers目录中,但随着业务越来越复杂,这样Controllers目录中的文件就增加 ...
- 网站上如何添加显示favicon
favicon.ico图标是网站的缩略标志,可以显示在浏览器标签.地址栏左边和收藏夹,是展示网站个性的缩略logo标志,也可以说是网站头像. 要添加显示favicon,步骤如下: 1.生成favi ...
- 安装XAMPP遇到的问题及解决方法
1.XAMPP无法启动Apache Xampp的获得和安装都十分简单,你只要到以下网址: http://www.apachefriends.org/zh_cn/xampp.html 下载xampp即可 ...
- SSH框架使用注解简化代码
注释的优势: 1.最简单直接的优势就是减少了配置文件的代码量. 2.注释和Java代码位于一个文件中,而XML 配置采用独立的配置文件.配置信息和 Java 代码放在一起,有助于增强程序的内聚性.而采 ...