131. 分割回文串-两种回溯思路

我们可以将字符串分割成若干回文子串,返回所有可能的方案。如果将问题分解,可以表示为分割长度为n-1的子字符串,这与原问题性质相同,因此可以采用递归方法解决。

为什么回溯与递归存在联系?在解决这个问题时,我们首先从短字符串开始构建(递的过程),当构造到最长字符串时,需要尝试其他方案(归的过程,即回溯)。

思路一:可以将每两个字符之间的位置视为一个可选的分割点。选择或不选择每个分割点会产生不同的字符串组合。例如,在示例一中,这种思路会产生四种不同的分割方案。

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​

关于递归边界条件的写法:使用下标i表示当前位置。当i达到字符串长度时,说明分割完成,此时将当前方案存入ans列表。

对于非边界情况:

  1. 选择当前位置作为分割点:

    • 若当前子串是回文,则将其加入临时方案path
    • 递归处理i+1位置
    • 递归完成后需恢复现场,弹出path最后一个元素(回溯操作)
  2. 不选择当前位置作为分割点:

    • 直接递归处理i+1位置
cpp 复制代码
class Solution {
public:
    vector<vector<string>> ans;
    vector<string> path;
    bool isPalindrome(string s,int left,int right) {
        while (left < right) {
            if (s[left++] != s[right--]) {
                return false;
            }
        }
        return true;
    }
    void dfs(int i,int n,string& s,int start) {
        if (i == n) {
            ans.emplace_back(path);
            return;
        }
        if (i < n - 1) dfs(i + 1,n,s,start);
        if(isPalindrome(s,start,i)) {
            path.push_back(s.substr(start,i - start + 1));
            dfs(i + 1,n,s,i + 1);
            path.pop_back();
        }
        
    }
    vector<vector<string>> partition(string s) {
        dfs(0,s.size(),s,0);
        return ans;
    }
};

思路二,答案的视角(枚举子串的结束位置)

我们以子串的结束位置j为基准,将当前回文子串加入候选路径,然后递归处理从j+1到n-1位置的剩余字符串分割问题。

cpp 复制代码
class Solution {
public:
    vector<vector<string>> ans;
    vector<string> path;
    bool isPalindrome(string s,int left,int right) {
        while (left < right) {
            if (s[left++] != s[right--]) {
                return false;
            }
        }
        return true;
    }
    void dfs(int i,int n,string& s) {
        if (i == n) {
            ans.emplace_back(path);
            return;
        }
        for(int j = i;j < n;j++) {
            if (isPalindrome(s,i,j)) {
                path.push_back(s.substr(i, j - i + 1));
                dfs(j + 1,n,s);
                path.pop_back();
            }
        }
        
    }
    vector<vector<string>> partition(string s) {
        dfs(0,s.size(),s);
        return ans;
    }
};

时间复杂度:O(n*2^n),递归次数为逗号的子集的个数,也就是2^n,在判断是否是会回文需要O(n)时间所以,总时间为O(n2^n)

空间复杂度:O(n)

相关推荐
码王吴彦祖21 小时前
顶象 AC 纯算法迁移实战:从补环境到纯算的完整拆解
java·前端·算法
SccTsAxR21 小时前
算法基石:手撕离散化、递归与分治
c++·经验分享·笔记·算法
wuweijianlove21 小时前
算法测试中的数据规模与时间复杂度匹配的技术4
算法
Q741_14721 小时前
每日一题 力扣 3655. 区间乘法查询后的异或 II 模拟 分治 乘法差分法 快速幂 C++ 题解
c++·算法·leetcode·模拟·快速幂·分治·差分法
The_Ticker21 小时前
印度股票实时行情API(低成本方案)
python·websocket·算法·金融·区块链
夏乌_Wx1 天前
剑指offer | 2.4数据结构相关题目
数据结构·c++·算法·剑指offer·c/c++
米啦啦.1 天前
C+类的友元与静态成员函数,类模板
c++·友元·类模板
超绝振刀怪1 天前
【C++可变模板参数】
开发语言·c++·可变模板参数
AI成长日志1 天前
【笔面试算法学习专栏】哈希表基础:两数之和与字母异位词分组
学习·算法·面试
minji...1 天前
Linux 线程同步与互斥(二) 线程同步,条件变量,pthread_cond_init/wait/signal/broadcast
linux·运维·开发语言·jvm·数据结构·c++