5. 最长回文子串

52 篇文章 0 订阅
44 篇文章 0 订阅

在这里插入图片描述
三种方法
1.暴力通过剪枝可以达到O(n^2)的时复
2.二维dp,此处需要用到二维dp,dp[i][j]存的是以i为头,j为首的字符串是否为回文串。根据回文串的性质来写转移方程。1.回文串两头相等。2.回文串去掉头尾还是回文串。我们用maxLen和begin来记录子串的起始位置和最大长度,不要每次都substr。因为这里是二维dp,二维dp最最重要的就是填表顺序,这里我的填表方式是一列一列填表,因为dp[i][j]要根据dp[i+1][j-1]来推断,刚好是左下角,所以一列一列填表是可以,而且只要填右上角部分就行。j从第1列开始,不是第0列,因为0,0一定是true,i从第0遍历到j-1,如果首尾不等,dp[i][j]就是false,如果相等,判断j-i+1是否<=3,也就是该子串的长度,如果小于3且首尾相等,那就是一个回文串。如果不<=3就根据左下角来判断。判断完dp[i][j]完后判断maxlen和j-i+1哪个大。时复和空复均为O(N^2)
3.中心扩散法:时复O(n^2),空复O(1)。遍历s每一位,将它往两边扩散(直到找到以它为中心不是回文串为止),left=i-1,right=i+1,如果s[left]==s[i]就将left–,right类似,直到找不到不等的。因为如果是相等的,aaaa不管几个a都是回文串。根据左右扩散,如果左右相等,就一直扩散。注意的是left和right的操作每一步都要判断是否越界。在left–和right++时都要将tmpLen加1,两边扩散时+2。最后判断的时候left+1才是真正的begin位,因为left已经构不成回文串了。

class Solution {
public:
    string longestPalindrome(string s) {
        //最长=最优解=dp
        if(s.length() < 2) return s;
        int n = s.length();
        //string res = "";
        //暴力,遍历i位,每次截取j位,记录最长的回文子串,通过reverse来判断,先暴力再考虑dp
        /*for(int i = 0; i < s.length(); ++i){
            for(int j = i; j < s.length(); ++j){
                string tmp = s.substr(i,j-i+1);
                string rev = tmp;
                reverse(rev.begin(),rev.end());
                if(tmp == rev && j-i+1>res.length()){
                    res = tmp;
                }
            }
        }
        return res;*/

        //此处需要用二维dp,通过回文子串的特性来推断状态转移方程
        //1.回文串两头相等。2.回文串去掉头尾还是回文串
        //dp[i][j]存的是以i为头,j为首的字符串是否是回文串
        //状态转移方程:dp[i][j]=
        //1.如果s[i]==s[j],dp[i][j]=dp[i+1][j-1],要从短判断到长,需要一列一列填表
        /*int maxLen = 1;
        int begin = 0;
        vector<vector<bool>> dp(n,vector<bool>(n));
        for(int j = 1; j < n; ++j){
            for(int i = 0; i < j; ++i){
                //不用i==j,因为dp[i][i]一定是回文,不用判断
                if(s[i] != s[j]){
                    dp[i][j] = false;
                }
                else if(s[i] == s[j]){
                    if(j-i+1<=3){
                        dp[i][j] = true;
                    }
                    else{
                        //不用判断越界,i+1最大等于j,j-1最小等于0
                        dp[i][j] = dp[i+1][j-1];
                    }
                }
                if(dp[i][j]&&j-i+1>maxLen){
                    begin = i;
                    maxLen = j-i+1;
                }
            }
        }
        return s.substr(begin,maxLen);*/

        //中心扩散法
        int left = 0, right = 0, maxLen = 1, begin = 0;
        for(int i = 0; i < n; ++i){
            left = i-1;
            right = i+1;
            int tmpLen = 1;
            while(left>=0 && s[i] == s[left]){
                tmpLen++;
                left--;
            }
            while(right<n && s[i] == s[right]){
                tmpLen++;
                right++;
            }
            while(left>=0 && right<n && s[left] == s[right]){
                left--;
                right++;
                tmpLen+=2;
            }
            if(tmpLen>maxLen){
                //应该是left+1,因为此时的left已经不是回文子串了
                begin = left+1;
                maxLen = tmpLen;
            }
        }
        return s.substr(begin,maxLen);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值