赞
踩
给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是 回文串 。返回 s
所有可能的分割方案。回文串 是正着读和反着读都一样的字符串
示例 1:
- 输入:s = "aab"
- 输出:[["a","a","b"],["aa","b"]]
示例 2:
- 输入:s = "a"
- 输出:[["a"]]
>>思路和分析:
代码随想录的Carl老师说:“切割问题类似组合问题”!(这段文字来自代码随想录--分割回文串)
对于字符串abcdef:
- 组合问题:选取一个a之后,在bcdef中再去选取第二个,选取b之后在cdef中再选取第三个.....
- 切割问题:切割一个a之后,在bcdef中再去切割第二段,切割b之后在cdef中再切割第三段.....
>>回溯三部曲:
1).确定回溯函数参数
- vector<vector<string>> result;
- vector<string> path; // 放已经回文的子串
- void backtracking (const string& s, int startIndex) // startIndex 就用来表示这条切割线
2).递归的终止条件
如果切割线切到了字符串最后面,表示找了一种切割方法,此时终止本层递归!也就是出现这种情况: startIndex >= s.size(),收集结果后直接return;
- void backtracking (const string& s, int startIndex) {
- // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
- if (startIndex >= s.size()) {
- result.push_back(path);
- return;
- }
- }
3).单层搜索的逻辑
>>问题(O_O)?思考:在递归循环中如何截取子串呢?
>>问题(O_O)?思考:如何判断所截取子串是否为回文子串呢?
- for (int i = startIndex; i < s.size(); i++) {
- if (isPalindrome(s, startIndex, i)) { // 是回文子串
- // 获取[startIndex,i]在s中的子串
- string str = s.substr(startIndex, i - startIndex + 1);
- path.push_back(str);
- } else { // 如果不是则直接跳过
- continue;
- }
- backtracking(s, i + 1); // 寻找i+1为起始位置的子串
- path.pop_back(); // 回溯过程,弹出本次已经添加的子串
- }
注意:切割过的位置,不能重复切割,应传入下一层的起始位置为 i + 1,即
(1)判断是否为回文子串
- 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;
- }
- bool isPalindrome(string s) {
- int left = 0,right = s.size()-1;
- while(left<=right) {
- if (s[left] != s[right]) return false;
- left++;
- right--;
- }
- return true;
- }
(2)C++代码
- class Solution {
- private:
- vector<vector<string>> result;
- vector<string> path; // 放已经回文的子串
- void backtracking (const string& s, int startIndex) {
- // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
- if (startIndex >= s.size()) {
- result.push_back(path);
- return;
- }
- for (int i = startIndex; i < s.size(); i++) {
- if (isPalindrome(s, startIndex, i)) { // 是回文子串
- // 获取[startIndex,i]在s中的子串
- string str = s.substr(startIndex, i - startIndex + 1);
- path.push_back(str);
- } else { // 不是回文,跳过
- continue;
- }
- backtracking(s, i + 1); // 寻找i+1为起始位置的子串
- path.pop_back(); // 回溯过程,弹出本次已经添加的子串
- }
- }
- 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;
- }
- public:
- vector<vector<string>> partition(string s) {
- backtracking(s, 0);
- return result;
- }
- };
- class Solution {
- public:
- vector<vector<string>> result;
- vector<string> path; // 放已经回文的子串
- bool isPalindrome(string s) {
- int left = 0,right = s.size()-1;
- while(left<=right) {
- if (s[left] != s[right]) return false;
- left++;
- right--;
- }
- return true;
- }
- void backtracking(string s,int startIndex) {
- // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
- if(startIndex >= s.size()) {
- result.push_back(path);
- return;
- }
- for(int i=startIndex;i<s.size();i++) {
- // 获取[startIndex,i]在s中的子串
- string subStr = s.substr(startIndex,i-startIndex+1);
- if(isPalindrome(subStr)) path.push_back(subStr);// 是回文子串
- else continue;// 不是回文,跳过
- backtracking(s, i + 1); // 寻找i+1为起始位置的子串
- path.pop_back(); // 回溯过程,弹出本次已经添加的子串
- }
- }
- vector<vector<string>> partition(string s) {
- backtracking(s, 0);
- return result;
- }
- };
参考和推荐文章、视频:
带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1c54y1e7k6/?p=67&spm_id_from=pageDriver代码随想录 (programmercarl.com)https://www.programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html#%E4%BC%98%E5%8C%96
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。