文章目录
1 题目
题目:分割回文串(Palindrome Partitioning)
描述:给定字符串 s,需要将它分割成一些子串,使得每个子串都是回文串。返回所有可能的分割方案。
- 不同的方案之间的顺序可以是任意的。
- 每种分割方案中的每个子串都必须是 s 中连续的一段。
样例1:
输入: "a"
输出: [["a"]]
解释: 字符串里只有一个字符, 也就只有一种分割方式 (就是它本身)
样例2:
输入: "aab"
输出: [["aa", "b"], ["a", "a", "b"]]
解释: 有两种分割的方式.
1. 将 "aab" 分割成 "aa" 和 "b", 它们都是回文的.
2. 将 "aab" 分割成 "a", "a" 和 "b", 它们全都是回文的.
2 解决方案
2.1 思路
要将整个串分割成回文串,必须将所有分割的可能情况都遍历一遍并逐一验证是否回文,对于这样遍历所有的操作,可以考虑使用深度优先搜索(Depth First Search)来找到所有分割子串。
2.2 时间复杂度
深度优先搜索的时间复杂度的计算方式是逻辑图上的节点数(即所有元素的组合数,n个元素,每个元素都有取或不取两种可能,所以是2的n次方)与处理每个节点的耗时的乘积,也可以看作答案个数与构造每个答案花费的时间的乘积,该题的算法的时间复杂度为O(2^n * n)。
2.3 空间复杂度
图上的宽度优先搜索,使用了vector数据结构保存节点,算法的空间复杂度为O(n)。
3 源码
细节:
- 该题使用常规方式进行DFS会需要更多临时变量来保存子串的相关信息(起点、长度等),这里使用一个技巧,将递归用的主串随着递归的深入进行不断缩减,这样可以简化代码逻辑,代码与标准DFS尽量一致。
C++版本:
/*
* @param s: A string
* @return: A list of lists of string
*/
vector<vector<string>> partition(string &s) {
// write your code here
vector<vector<string>> results;
if (s.empty())
{
return results;
}
vector<string> path;
dfs(s, path, results);
return results;
}
void dfs(string s, vector<string> path, vector<vector<string>> & results)
{
if (s.empty())
{
results.push_back(path);
return;
}
for (int i = 0; i < s.size(); i++)
{
if (isPalindrome(s.substr(0, i + 1)))
{
path.push_back(s.substr(0, i + 1));
dfs(s.substr(i + 1), path, results);
path.pop_back();
}
}
}
bool isPalindrome(const string & s)
{
int left = 0;
int right = s.size() - 1;
while (left < right)
{
if (s.at(left) != s.at(right))
{
return false;
}
left++;
right--;
}
return true;
}