- 131.分割回文串
- 思路:
要想把一个string分割为几个子string串,且必须都是回文串。由于分割位置任意,分割次数也任意(即没要求分成几块);
因此考虑回溯法遍历,将每个位置都尝试作为分割处;若某个字串不是回文,则尝试将分割线后移,也就是说,不能出现两个回文串中间夹一个非回文串的情形,必须是连着都是回文串;那我们就必须要求,若从i位置开始找的话,分别尝试从i开始长度为1的字串,为2的字串。。。分别去判断是不是回文串,假如说[i, i+1]这一段是个回文串,那么才能尝试从i+2以起始点寻找下一个回文串;若以i为起始点往后找,一直找到string主串末尾都没找到回文串,说明按前面分割的思路分到i-1得到的若干子串都是满足回文的,但从i开始后面找不到了,那么此时遍历到主串末尾时就不能将这种分割方法添加到结果集里面去。只有每次分割位置得到的都是回文串时,遍历到主串末尾才能把这种分割方法添加到结果集;
难点:
- 切割问题可以抽象为组合问题:即把主串分成连续的几大块
- 如何模拟那些切割线:用startIndex表示切割位置,即将startIndex-1及以前的部分跟后面隔开,尝试从以startIndex为后面那部分的起始位置去寻找回文串
- 切割问题中递归如何终止:分割到主串末尾(即startIndex >= s.size())
- 在递归循环中如何截取子串:
s.substr(int pos, int len);
- 如何判断一个字符串是不是回文:双指针
class Solution {
private:
vector<vector<string>> res;
vector<string> path;
bool ispalindrome (const string& str) {
int len = str.size();
if (len == 1) return true;
for(int i = 0, j = len - 1; i <= j; ++i, --j) {
if (str[i] != str[j]) return false;
}
return true;
}
void backtracking (const string& s, int stratIndex) {
if (stratIndex >= s.size()) {
res.push_back(path);
return;
}
for(int i = stratIndex; i < s.size(); ++i) {
string tmp = s.substr(stratIndex, i - stratIndex + 1);
if (ispalindrome(tmp)) path.push_back(tmp);
else continue;
backtracking(s, i + 1);
path.pop_back();
}
}
public:
vector<vector<string>> partition(string s) {
backtracking(s, 0);
return res;
}
};
- 切割问题可以抽象为组合问题;
- 切割问题用回溯;
- 通过传递参数为主串和int startIndex来模拟切割线;
当前切割位置为startIndex(startIndex前面可能已经经过多次切割了),startIndex只是说明最近的一次切割为此处,即将从startIndex开始往后寻找下一个切割位置;
- 终止条件为切割到主串末尾;
- 用substr函数来取子串;
string::substr(int pos, int len);
- 切割过的位置不能重复切割,因此必须传递i + 1而不能是i;