回文串

回溯

分割回文串

image

思路

回溯模板:每次传入起始位置,for循环遍历不同子串,若子串回文则递归;直到起始位置==s.size()

代码

class Solution {
public:
    vector<vector<string>> result;
    vector<string> path;
    void backTracking(string s,int index){
        if(index == s.size()){
            result.emplace_back(path);
            return;
        }
        for(int i=0;i<s.size()-index;i++){
            string subs = s.substr(index,i+1);
            if(!IsHuiwen(subs))continue;
            path.emplace_back(subs);
            backTracking(s,index+i+1);
            path.pop_back();
        }
    } 
    bool IsHuiwen(string s){
        int left=0,right=s.size()-1;
        while(left<=right){
            if(s[left]!=s[right])return false;
            left++;
            right--;
        }
        return true;
    }

    vector<vector<string>> partition(string s) {
        backTracking(s,0);
        return result;
    }
};

动态规划

回文子串

image

思路

DP数组直接令为dp[i]表示以下标i结尾的字符串有 dp[i]个回文串的话,很难找到和dp[i-1],dp[i+1]的关系

根据回文串的性质:若要判定s[i..j]是否回文,可判定s[i+1..j-1]是否回文 & s[i] == s[j]
因此dp数组令为二维数组dp[i][j]表示s[i..j]是否回文。

递推公式:

s[i]==s[j]时:

  • 子串长度为1 或 2 ,dp[i][j] = true
  • 否则dp[i][j] = dp[i+1][j-1]

遍历顺序

由于要用到dp[i+1][j-1],因此必须从下至上,从左至右遍历

代码

class Solution {
public:
    int countSubstrings(string s) {
        int n = s.size();
        vector<vector<bool>> dp(n,vector<bool>(n,false));
        //dp[i][j]表示s[i]-s[j]的子串是回文子串
        int result=0;//每判断有一个回文字串就+1
        for(int i=n-1;i>-1;i--){// 从下到上
            for(int j=i;j<n;j++){// 从左往右
                if(s[i] == s[j]){
                    if(j - i <= 1 || dp[i+1][j-1]){//i==j 和i+1 == j 
                        result++;
                        dp[i][j] = true;
                    // }else if(dp[i+1][j-1]){//i+1<j时,看区间[i+1,j-1]是否是回文
                    //     result++;
                    //     dp[i][j] = true;// 如果是则[i,j]也是回文
                    }
                }
            }
        }
        return result;
    }
};

最长回文子串

image

整体代码和回文子串一样

代码

class Solution {
public:

    string longestPalindrome(string s) {
        int len = s.size();
        vector<vector<bool>> dp(len,vector<bool>(len,false));//dp[i][j]表示s[i...j]是否是回文串
        int maxlen=0;
        int begin=0;
        // 递推公式 要看dp[i+1][j-1] 所以遍历要从下到上,从左往右
        for(int i=len-1;i>-1;i--){
            for(int j=i;j<len;j++){// i<=j 所以让j从i开始,其他的s[i...j]是非法字符串
                if(s[i] == s[j]){
                    if(j-i < 2 || dp[i+1][j-1]){
                        dp[i][j] = true;
                        if (j - i + 1 > maxlen){
                            begin = i;
                            maxlen = j-i+1;
                        }
                    }
                }
            }
        }
        return s.substr(begin,maxlen);
    }
};

双指针法 / 中心拓展法(优化空间复杂度O(1))

“回文子串”也适用

思路

选取一个中心,根据中心向两边拓展,如果两边相等就是回文串。
一个元素可以作为中心点,两个元素也可以作为中心点。但三个四个可由一个两个拓展来所以不必。

代码

  • for循环遍历中心点
  • extend向两边拓展
  • 记录最长字符串的起始点和长度最后substr
class Solution {
public:
    int maxlen=0;
    int left=0;

    void extend(const string& s,int i,int j,int n){//i和j是中心
        while(i >=0 && j < n && s[i] == s[j]){// 当前是回文串
            if(j - i + 1 > maxlen){
                maxlen = j-i+1;
                left = i;
            }
            i--;
            j++;
        }
    }

    string longestPalindrome(string s) {
        int n = s.size();
        if(n == 1)return s;

        for(int i=0;i<n;i++){
            extend(s,i,i,s.size());
            extend(s,i,i+1,s.size());
        }
        return s.substr(left,maxlen);

    }

};
posted @   NeroMegumi  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示