字符串处理 —— 回文串相关 —— 求最长回文子串

【暴力枚举】

求最长回文串最容易的方法就是暴力枚举,求出字符串的每一个子串,然后判断是不是回文,找到最长的那个回文串

求每一个子串的时间复杂度为 O(N^2),判断一个子串是不是回文时间复杂度为 O(N),总的时间复杂度为 O(N^3)

string str;
void longestPalindrome(){
    int len=str.size();//字符串长度
    int maxlen=1;//最长回文串长度
    int start=0;//最长回文串起始地址
    for(int i=0;i<len;i++){//起始地址
        for(int j=i+1;j<len;j++){//结束地址

            //判断是不是回文
            int temp1=i,temp2=j;
            while(temp1<temp2 && str.at(temp1)==str.at(temp2)){
                temp1++;
                temp2--;
            }
            if(temp1>=temp2&&j-i+1>maxlen){
                start=i;//更新回文串起始地址
                maxlen=j-i+1;//更新回文串长度
            }

        }
    }
    str=str.substr(start, maxlen);
}
int main(){
    cin>>str;
    longestPalindrome();
    cout<<str<<endl;;
    return 0;
}

【中心扩展法】

中心扩展就是将给定的字符串的每一个字母当做中心,然后向两边扩展,这样来寻找最长的回文串。其需要考虑两种情况:长度为奇数的回文串、长度为偶数的回文串。

时间复杂度为 O(N^2)

string str;
void longestPalindrome(){
    int len=str.size();//字符串长度
    int maxlen=1;//最长回文串长度
    int start=0;//最长回文串起始位置

    //长度为奇数的回文串
    for(int i=0;i<len;i++){//枚举中心位置
        int left=i-1,right=i+1;//以i为中心向左右两边扩展
        while(left>=0 && right<len && str.at(left)==str.at(right)){
            if(right-left+1>maxlen){
                start=left;//更新回文串起始位置
                maxlen=right-left+1;//更新回文串长度
            }
            left--;
            right++;
        }
    }

    //长度为偶数的回文串
    for(int i=0;i<len;i++){//枚举中心位置
        int left=i,right=i+1;//以i为中心向左右两边扩展
        while(left>=0 && right<len && str.at(left)==str.at(right)){
            if(right-left+1>maxlen){
                start=left;//更新回文串起始位置
                maxlen=right-left+1;//更新回文串长度
            }
            left--;
            right++;
        }
    }

    str=str.substr(start, maxlen);
}
int main(){
    cin>>str;
    longestPalindrome();
    cout <<str<<endl;
    return 0;
}

【动态规划】

设 dp[j][i] 表示从 j 到 i 的子串是否是回文串,则:

dp[j][i]=\left\{\begin{matrix}true,\:\:j=i \\ str[i]=str[j],\:\:i-j=1 \\ str[i]=str[j],dp[j][i-1]=true,\:\:i-j>1 \end{matrix}\right.

当 dp[j][i]=true 时,表示从 j 到 i 的子串为回文子串,且子串起点位置为 j,长度为 i - j + 1

时间复杂度为:O(N ^ 2)

string str;
bool dp[N][N];
void longestPalindrome(){
    memset(dp,false,sizeof(dp));

    int len=str.size();//字符串长度
    int start=0;//最长回文子串起点
    int maxlen=1;//最长回文子串长度

    for(int i=0;i<len;i++){//字符串终点
        for(int j=0;j<=i;j++){//字符串起点
            if(i-j<2)
                dp[j][i]=(str[i]==str[j]);
            else
                dp[j][i]=(str[i]==str[j] && dp[j+1][i-1]);

            if(dp[j][i] && maxlen<i-j+1){
                start=j;//更新回文串起点
                maxlen=i-j+1;//更新回文串长度
            }
        }
    }

    str=str.substr(start, maxlen);
}

int main(){
    cin>>str;
    longestPalindrome();
    cout<<str<<endl;
    return 0;
}

【Manacher 算法】

时间复杂度:O(N)

算法详解:点击这里

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值