最长回文子串(暴力算法和马拉车算法)

本文介绍了两种寻找字符串中最长回文子串的方法:暴力求解和Manacher算法。暴力方法的时间复杂度为O(n^2),而Manacher算法通过预处理和动态维护回文半径,将时间复杂度降低到O(n)。文章详细解释了两种算法的实现细节,并提供了Java代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回文字符串 (palindrome)

Find the longest substring in the string

  1. Force way

区分奇偶回文字符串
找最长奇数回文字符串需逐个从单个字符串向两边扩展
找最长偶数回文字符串需逐个从两个字符串中间向两边扩展

在这里插入图片描述

代码实现 O(n^2)

public class Main {

    public static int expend (int left , int  right , String s ){


        int l = left;
        int r = right;

        int res = 0 ;

        while(l>=0&&r<s.length()&&s.charAt(l)==s.charAt(r)){

            res = r- l + 1;
            l--;
            r++;

        }

        return  res;

    }


    public static void main(String[] args) {

     Scanner cin  = new Scanner(System.in);


     String str = cin.next();
        int ans = 0;


        for(int i = 0 ;i <str.length();i++){

            int max1 = expend(i,i,str);   //奇数
            int max2 = expend(i,i+1,str); //偶数
            int res = Math.max(max1,max2); //比较最大值

              ans = Math.max(ans,res); //结果最大值

        }
        System.out.println(ans);

    }

}

  1. Manacher

在字符串首尾和字符间添加相同任意字符,使字符串中的回文字符串一直为奇数字符串

如 abba -> #a#b#b#a# abcbd -> #a#b#c#b#d#

使用数组来记录以每个字符为回文中心的回文半径
使用R来记录当前最大回文串的最右坐标的下位
使用C来记录当前最大回文串的中心坐标

在这里插入图片描述

分当前查找字符在R内部和在R外部来讨论

代码实现 O(n)

public class Main {



    static String toManacher(String s){


        StringBuilder str = new StringBuilder();

        str.append("#");

        for(int i = 0 ; i < s.length(); i++){


            str.append(s.charAt(i));


            str.append("#");


        }

        return str.toString();

    }



    public static void main(String[] args) {


        Scanner cin = new Scanner(System.in);

        String s = cin.next();

        s = toManacher(s); //添加#号

        int R = -1; // 当前最右回文边界下一位
        int C = -1; // 当前最长回文中心
        int Max= Integer.MIN_VALUE;



        int[] parr = new int[s.length()];//记录回文半径



        for(int i = 0 ; i < s.length() ;i++){


            parr[i] = R > i ? Math.min(parr[2*C-i],R-i) : 1;


            while((i-parr[i]>=0) && (i+parr[i] < s.length())) {

                if (s.charAt(i - parr[i]) == s.charAt(i + parr[i])) {

                    parr[i]++;

                } else {

                    break;


                }
            }

                if(i+parr[i] > R){
                    R = i+parr[i]; //更新最右边界
                    C = i;//更新中心位置

                }



            Max = Math.max(parr[i]-1,Max);



        }



        System.out.println(Max);


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值