0
点赞
收藏
分享

微信扫一扫

力扣第131题 分割回文串 c++ 回溯+简单 动态规划(是否为回文子串)

题目

131. 分割回文串

中等

相关标签

字符串   动态规划   回溯

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

回文串 是正着读和反着读都一样的字符串。

示例 1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"
输出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

思路和解题方法一 回溯+判断

复杂度

        时间复杂度:

                O(2^n * n)

        空间复杂度

                O(n^2)

c++ 代码一

class Solution {
public:
    vector<vector<string>> ans; // 存储结果的二维向量
    vector<string> path; // 存储当前路径的一维向量
    
    void backtrackint(string &s, int index) {
        if (index >= s.size()) { // 如果遍历到字符串末尾,将当前路径添加到结果中
            ans.push_back(path);
            return;
        }
        for (int i = index; i < s.size(); i++) { // 遍历字符串,从当前位置开始
            if (ifhuimen(s, index, i)) { // 判断从当前位置到 i 是否是回文子串
                string str = s.substr(index, i - index + 1); // 获取回文子串
                path.push_back(str); // 将回文子串加入当前路径
            } else {
                continue; // 如果不是回文子串,跳过当前位置
            }
            backtrackint(s, i + 1); // 递归处理剩余部分
            path.pop_back(); // 回溯,将当前路径的最后一个元素移除
        }
    }

    bool ifhuimen(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;
    }

    vector<vector<string>> partition(string s) {
        ans.clear(); // 清空结果向量
        path.clear(); // 清空路径向量
        backtrackint(s, 0); // 回溯搜索所有回文子串的组合
        return ans; // 返回结果向量
    }
};

思路和解题方法二 回溯+动态规划

复杂度 和上面一样

        时间复杂度:

                O(2^n * n)

        空间复杂度

                O(n^2)

c++ 代码二

class Solution {
private:
    vector<vector<string>> result;               // 存储最终的分割结果
    vector<string> path;                         // 存储已经回文的子串
    vector<vector<bool>> isPalindrome;           // 存储事先计算好的是否回文子串的结果

    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[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();                        // 回溯过程,弹出本次已经添加的子串
        }
    }

    void computePalindrome(const string& s) {
        // isPalindrome[i][j] 代表 s[i:j](双边包括)是否是回文字串 
        isPalindrome.resize(s.size(), vector<bool>(s.size(), false));  // 根据字符串s,刷新布尔矩阵的大小

        for (int i = s.size() - 1; i >= 0; i--) { 
            // 需要倒序计算,保证在i行时,i+1行已经计算好了
            for (int j = i; j < s.size(); j++) {
                if (j == i) {
                    isPalindrome[i][j] = true;
                } else if (j - i == 1) {
                    isPalindrome[i][j] = (s[i] == s[j]);
                } else {
                    isPalindrome[i][j] = (s[i] == s[j] && isPalindrome[i + 1][j - 1]);
                }
            }
        }
    }

public:
    vector<vector<string>> partition(string s) {
        result.clear();
        path.clear();
        computePalindrome(s);        // 计算是否回文子串
        backtracking(s, 0);          // 回溯得到分割结果
        return result;
    }
};

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

举报

相关推荐

0 条评论