HOT61-分割回文串

         leetcode原题链接:分割回文串

题目描述

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

示例 1:

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

示例 2:

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

提示:

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

解题方法: 回溯法。定义backtrack(s, i, tmp, result)表示以i为当前分割的起点,从[i, n)中获取回文串。然后遍历不同的j=i+len,如果[i,j]是回文串,则下一段查找从j+1开始,详细见代码注释。另外,值得一提的是如何判断s[i...j]是否为回文串,方法如下:

方法1: 双指针法(在本题中的缺陷是有重复计算)

方法2: 动态规划法。dp[i][j]表示str[i...j]是否为回文串

dp[i-1][j+1] = dp[i][j] && s[i-1]==s[j+1]

从左右等号两边的i,j关系可以看出,二维数组初始化遍历的顺序i是从大到下,j是从小到大。

C++代码

#include 
#include 
#include  
/*
   abcb
   方法1: 双指针法(在本题中的缺陷是有重复计算)
   方法2: 动态规划法。dp[i][j]表示str[i...j]是否为回文串
   dp[i-1][j+1] = dp[i][j] && s[i-1]==s[j+1]

*/
class Solution {
public:
    std::vector> partition(std::string s) {
        std::vector tmp;
        std::vector> result;
        backtrack(s, 0, tmp, result);
        return result;
    }

    void backtrack(const std::string& s,
                   int i,
                   std::vector& tmp,
                   std::vector>& result) { //以i为起点
        int n = s.size();
        if (i == n) {
            result.emplace_back(tmp);
        }
        for (int j = i; j < n; j++) {
            int len = j - i + 1; // [i, ..., j]
            if (check(s, i, j)) { // 判断 [i, j]是否为回文串
                tmp.push_back(s.substr(i, len)); // 选择[i...j]
                backtrack(s, j + 1, tmp, result); //继续从j的下一个位置开始选择
                tmp.pop_back(); //撤销选择
            }
        }
        
    }
    // 判断s[i,...,j]是否为回文串,这里用的是最朴素的方法。
    // 当然可以用动态规划优化,可以减少重复计算:
    // 动态规划优化的方法是用dp[i][j]保存s[i,...,j]是否为回文串
    //    状态转移方程:dp[i-1][j+1] = dp[i][j] && s[i-1]==s[j+1]
    //    初始化顺序:i从大到小,j从小到大 (根据等号两边i,j的大小可以看出)
    bool check(const std::string& s, int i, int j) {
        while (i <= j) {
            if (s[i] != s[j]) {
                return false;
            }
            i++;
            j--;
        }
        return true;
    }

};

你可能感兴趣的:(leetcode最热100题,算法,数据结构,leetcode,回溯)