leetcode 回文字符串(总结)

一、LeetCode 647 回文子串
题目描述:
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

思路:
循环遍历查找子串

代码如下:

class Solution {
public:
    int countSubstrings(string s) {
        int n=s.size();
        int res=0;
        vector<vector<int>>dp(n,vector<int>(n,0));
        for(int i=0;i<n;i++){
            dp[i][i]=1;
            res++;
            for(int j=i-1;j>=0;j--){
                if(s[i]==s[j]&&(j+1==i||dp[i-1][j+1])){
                    dp[i][j]=1;
                    res++;
                }
            }
        }
        return res;
    }
};

二、LeetCode 730 统计不同回文子序列
题目描述:
给定一个字符串 S,找出 S 中不同的非空回文子序列个数,并返回该数字与 10^9 + 7 的模。

通过从 S 中删除 0 个或多个字符来获得子序列。

如果一个字符序列与它反转后的字符序列一致,那么它是回文字符序列。

如果对于某个 i,A_i != B_i,那么 A_1, A_2, … 和 B_1, B_2, … 这两个字符序列是不同的。

思路:
参考题解此处

代码如下:

class Solution {
public:
    int countPalindromicSubsequences(string S) {
        int n=S.size();
        vector<vector<int>>f(n,vector<int>(n,0));
        for(int i=0;i<n;i++){
            f[i][i]=1;
        }
        int mod=1000000007;
        for(int i=n-2;i>=0;i--){
            for(int j=i+1;j<n;j++){
                if(S[i]!=S[j]){
                    f[i][j]=f[i+1][j]+f[i][j-1]-f[i+1][j-1];
                }
                else{
                    f[i][j]=f[i+1][j-1]*2+2;
                    int l=i+1,r=j-1;
                    while(l<=r&&S[l]!=S[i]) l++;
                    while(l<=r&&S[r]!=S[i]) r--;
                    if(l==r) f[i][j]--;
                    else if(l<r) f[i][j]-=2+f[l+1][r-1];
                }
                f[i][j]=(f[i][j]>=0)?f[i][j]%mod:f[i][j]+mod;
            }
        }
        return f[0][n-1];
    }
};

三、LeetCode 1745 回文串分割IV
题目描述:
给你一个字符串 s ,如果可以将它分割成三个 非空 回文子字符串,那么返回 true ,否则返回 false 。

当一个字符串正着读和反着读是一模一样的,就称其为 回文字符串 。

思路:
首先统计每个子串是否是回文串
然后再开始分割

代码如下:

class Solution {
public:
    bool checkPartitioning(string s) {
        int n=s.size();
        vector<vector<int>>dp(n,vector<int>(n,0));
        for(int i=0;i<n;i++){
            dp[i][i]=1;
            if(i<n-1&&s[i]==s[i+1]){
                dp[i][i+1]=1;
            }
        }
        for(int len=3;len<=n;len++){
            for(int i=0;i+len-1<=n-1;i++){
                int j=i+len-1;
                if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]; 
            }
        }
        for(int i=0;i<=n-3;i++){
            for(int j=i+1;j<=n-2;j++){
                if(dp[0][i]&&dp[i+1][j]&&dp[j+1][n-1]) return true;
            }
        }
        return false;
    }
};

四、LeetCode 131 分割回文串
题目描述:
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

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

思路:
递归查找

代码如下:

class Solution {
public:
    vector<vector<string>> partition(string s) {
        vector<vector<string>>res;
        vector<string>path;
        if(s.size()==0) return res;
        dfs(s,0,path,res);
        return res;
    }
    void dfs(string s,int cur,vector<string>&path,vector<vector<string>>&res){
        if(cur==s.size()){
            res.push_back(path);
        }
        for(int end=cur+1;end<=s.size();end++){
            string ss=s.substr(cur,end-cur);
            if(!isPalindrome(ss)) continue;
            path.push_back(ss);
            dfs(s,end,path,res);
            path.pop_back();
        }
    }
    bool isPalindrome(string s){
        int l=0,r=s.size()-1;
        while(l<r){
            if(s[l]!=s[r]){
                return false;
            }
            l++;
            r--;
        }
        return true;
    }
};

五、LeetCode 132 分割回文串II
题目描述:
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。

返回符合要求的 最少分割次数 。

思路:
首先统计每个子串是否是回文串
然后再进行查找,找到最小的分割方法

代码如下:

class Solution {
public:
    int minCut(string s) {
        int n=s.size();
        vector<vector<bool>>g(n,vector<bool>(n,true));
        vector<int>f(n,INT_MAX);
        for(int i=n-1;i>=0;i--){
            for(int j=i+1;j<n;j++){
                g[j][i]=(s[i]==s[j])&&g[i+1][j-1];
            }
        }
        for(int i=0;i<n;i++){
            if(g[0][i]){
                f[i]=0;
            }
            else{
                for(int j=0;j<i;j++){
                    if(g[j][i]){
                        f[i]=min(f[i],f[j]+1);
                    }
                }
            }
        }
        return f[n-1];
    }
};

六、LeetCode 1278 分割回文串III
题目描述:
给你一个由小写字母组成的字符串 s,和一个整数 k。

请你按下面的要求分割字符串:

首先,你可以将 s 中的部分字符修改为其他的小写英文字母。
接着,你需要把 s 分割成 k 个非空且不相交的子串,并且每个子串都是回文串。
请返回以这种方式分割字符串所需修改的最少字符数。

思路:
首先利用动态规划,统计每个子串的长度

代码如下:

class Solution {
public:
    int palindromePartition(string s, int k) {
        int n=s.size();
        vector<vector<int>>cost(n,vector<int>(n,0));
        for(int i=n-1;i>=0;i--){
            for(int j=i+1;j<n;j++){
                if(s[i]==s[j]){
                    cost[i][j]=cost[i+1][j-1];
                }
                else{
                    cost[i][j]=cost[i+1][j-1]+1;
                }
            }
        }
        vector<vector<int>>f(n+1,vector<int>(k+1,INT_MAX));
        f[0][0]=0;
        for(int i=1;i<=n;i++){
            f[i][1]=cost[0][i-1];//分成一份的话,就是整段消耗的长度
            for(int j=2;j<=k&&j<=i;j++){//分成j份
                for(int t=i;t>=j;t--){
                    f[i][j]=min(f[i][j],f[t-1][j-1]+cost[t-1][i-1]);
                }
            }
        }
        return f[n][k];
    }
};

七、LeetCode 5 最长回文子串
题目描述:
给你一个字符串 s,找到 s 中最长的回文子串。

思路:
动态规划,寻找每个子串是否是回文串,如果是回文串,判断是否是更长的子串

代码如下:

class Solution {
public:
    string longestPalindrome(string s) {
        int n=s.size();
        if(n<1) return 0;
        vector<vector<int>>dp(n,vector<int>(n,0));
        int res=1,start=0;
        for(int i=n-1;i>=0;i--){
            dp[i][i]=1;
            for(int j=i+1;j<n;j++){
                if(s[i]==s[j]) {
                    if(i+1==j) dp[i][j]=1;
                    else dp[i][j]=dp[i+1][j-1];
                }
                else dp[i][j]=0;
                if(dp[i][j]&&res<j-i+1){
                    res=j-i+1;
                    start=i;
                }
            }
        }
        return s.substr(start,res);
    }
};

八、LeetCode 214 最短回文子串
题目描述:
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

思路:
首先反转字符串
然后比较最长的子串,是否相等
最后返回
代码如下:

class Solution:
    def shortestPalindrome(self, s: str) -> str:
        length=len(s)
        if length==0:
            return ""
        rs=s[::-1]
        i=0
        while True:
            if(rs[i:]==s[:length-i]):
                break
            else:
                i+=1
        return rs[:i]+s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值