代码随想录Day23
131.分割回文串
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串。返回 s 所有可能的分割方案。
示例 1:
输入:s = "aab" 输出:[["a","a","b"],["aa","b"]]
示例 2:
输入:s = "a" 输出:[["a"]]
提示:
1 <= s.length <= 16
s 仅由小写英文字母组成
正解(回溯)
其实切割问题和组合问题本质上是一样的。
那么切割问题就也可以抽象成树:
递归用来纵向遍历,for循环用来横向遍历,切割线(就是图中的红线)切割到字符串的结尾位置,说明找到了一个切割方法。
- 递归函数参数
全局变量数组path存放切割后回文的子串,二维数组result存放结果集。 (这两个参数可以放到函数参数里)
本题递归函数参数还需要startIndex,因为切割过的地方,不能重复切割,和组合问题也是保持一致的 - 递归函数终止条件
从树形结构的图中可以看出:切割线切到了字符串最后面,说明找到了一种切割方法,此时就是本层递归的终止条件。
那么在代码里什么是切割线呢?
在处理组合问题的时候,递归参数需要传入startIndex,表示下一轮递归遍历的起始位置,这个startIndex就是切割线。 - 单层搜索的逻辑
来看看在递归循环中如何截取子串呢?
首先判断这个子串是不是回文,如果是回文,就加入
上代码(●'◡'●)
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) { result.clear(); path.clear(); backtracking(s, 0); return result; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具