leetcode:131. 分割回文串 - 力扣(LeetCode)
题目
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例: 输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ]
思路
首先解决回文串的问题,之前做过类似的,运用对称思想或者双指针判断:
// 判断字符串s的子串是否为回文串
bool isPalindrome(const string &s, int start, int end)
{
// 从子串的两端开始,向中间遍历
for (int i = start, j = end; i < j; i++, j--)
{
// 如果发现两端的字符不相等,则子串不是回文串
if (s[i] != s[j])
return false;
}
// 如果所有对应的字符都相等,则子串是回文串
return true;
}
所以接下来的主要问题是怎么分割?
字符的分割图如下:
这里就跟前面的组合问题很像,这里的分割线是啥呢?其实就是startIndex!
什么时候切割结束?就是startIndex到了s.size(),此时收集结果:
if (startIndex >= s.size())
{
result.push_back(path);
return;
}
怎么在循环里面截取子串?
子串的范围是[startIndex,i],然后使用isValid来判断是否为回文子串,如果是回文,就加入到path,path用来记录切割过的回文子串。
for (int i = startIndex; i < s.size(); i++)
{
if (isPalindrome(s, startIndex, i))
{
string str = s.substr(startIndex, i - startIndex + 1);
path.push_back(str);
}
else
continue;
backtracking(s, i + 1);
path.pop_back();
}
子串str的获取方式用的是substr函数,获取当前这一段的字符串。
切割过的位置不可以重复切割,所以backtracking里面接的是i+1。
整体代码如下:
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
private:
vector<vector<string>> result;
vector<string> path;
// 判断字符串s的子串是否为回文串
bool isPalindrome(const string &s, int start, int end)
{
// 从子串的两端开始,向中间遍历
for (int i = start, j = end; i < j; i++, j--)
{
// 如果发现两端的字符不相等,则子串不是回文串
if (s[i] != s[j])
return false;
}
// 如果所有对应的字符都相等,则子串是回文串
return true;
}
void backtracking(const string &s, int startIndex)
{
if (startIndex >= s.size())
{
result.push_back(path);
return;
}
for (int i = startIndex; i < s.size(); i++)
{
if (isPalindrome(s, startIndex, i))
{
string str = s.substr(startIndex, i - startIndex + 1);
path.push_back(str);
}
else
continue;
backtracking(s, i + 1);
path.pop_back();
}
}
public:
vector<vector<string>> partition(string s)
{
result.clear();
path.clear();
backtracking(s, 0);
return result;
}
};
总结
切割问题跟组合问题很像,切割也要求不可以重复切割,所以需要用一个startIndex来指定每次切割的起始位置。