最长回文子串

回文,亦称回环,是正读反读都能一样的字符串。例如“12321”、“abba”等。
现在给你一个字符串,请你找出其中长度最长的回文。

输入描述:
输入有多组数据。
每组数据有一行,包含一个长度小于100个字符的字符串s,且仅由字母和数字构成。
如果有多个长度相等的回文,仅输出第一个。

输出描述:
对应每一组输入,输出其中长度最长的回文字符串。

/**
 * 最长回文子串求解的四种方法
 */
public class GetPalindrome {

    public static void main(String[] args) {
        /*System.out.println(new GetPalindrome().getPalindrome("abc1234321caa"));*/
        /*System.out.println(new GetPalindrome().getPalindromeByCenter("abcdaa"));*/
        /*System.out.println(new GetPalindrome().getpalindromeDP("abc1234321caa"));*/
        new GetPalindrome().getPalindromeManacher("abc1234321caa");
    }
    /**
     * 暴力求解法
     * 时间复杂度O(N^3)
     * @param source
     * @return
     */
    public String getPalindrom(String source){
        int len = source.length();
        String str;
        int start = 0;
        /*
         * length更新子串长度
         */
        int length = 1;
        int end = 1;
        for(int i = 0;i<len;i++){
            for(int j = i+1;j<len;j++){
                str = source.substring(i,j+1);
                if(isPalindrom(str)){
                    int size = j-i+1;
                    if(size>length){
                        length = size;
                        start = i;
                        end = j+1;
                    }
                }
            }
        }
        return source.substring(start,end);
    }
    /**
     * 判断子串是否是回文子串
     * @param s
     * @return
     */
    public boolean isPalindrom(String s){
        int start = 0;
        int end = s.length()-1;
        while(start<end){
            if(s.charAt(start)!= s.charAt(end)){
                return false;
            }
            start++;
            end--;
        }
        return true;
    }









    /**
     * 中心法
     * 时间复杂度O(N^2)
     * @param source
     * @return
     */
    public String getPalindromeByCenter(String source){
       int length = source.length();
       int size = 1;
       String str ;
       String subString = "";

       for(int i = 0;i<length;i++){
           /*
            * 以下标i位置的元素为对称中心
            */
           str = palindromeByCenter(source, i, i);
           if(str.length()>size){
               size = str.length();
               subString = str;
           }
           /*
            * 以下标i和i+1之间的空隙为对称中心
            */
           str = palindromeByCenter(source, i, i+1);
           if(str.length()>size){
               size = str.length();
               subString = str;
           }
       }
       return subString;

    }
    /**
     * 中心法求最长回文子序列
     * @param s
     * @param i
     * @param j
     * @return
     */
    public String palindromeByCenter(String s,int i,int j){
        int len = s.length()-1;
        while(i>=0&&j<=len&&s.charAt(i)==s.charAt(j)){
            i--;
            j++;
        }
        return s.substring(i+1,j);
    }

    /**
     * 动态规划求解
     * 时间复杂度O(N^2)
     * @param source
     * @return
     * 令F[i,j] = 1 表示i到j的序列是回文序列。
     *  F[i,i] = 1;
     *  F[i,i+1]=1; S[i]=S[i+1];
     *  F[i+1,j-1]=1&&S[i]=S[j] =>  F[i,j]=1
     */
    public String getpalindromeDP(String source){
        int N = source.length();
        int[][] dp = new int[N][N];
        int size = 1;
        int start = 0;
        for(int i = 0;i<N;i++) {
            dp[i][i] = 1;
        }
        for(int i = 0;i<N-1;i++){
            if(source.charAt(i)==source.charAt(i+1)){
                dp[i][i+1] = 1;
                size = 2;
                start = i;
            }
        }
        /**
         * sec 代表步长,从2到N-1
         */
        for(int sec = 2;sec<=N-1;sec++){
            for(int i = 0;i<N-sec;i++){
                int j = i+sec;
                if(source.charAt(i)==source.charAt(j)&&dp[i+1][j-1]==1){
                    dp[i][j] = 1;
                    start = i;
                    size = j-i+1;
                }
            }
        }
        return source.substring(start,start+size);
    }

    /**
     * Manacher算法
     * 时间复杂度O(N)
     * @param s
     */
    public  void  getPalindromeManacher(String s){
        int N = s.length();
        /*
         * 处理原字符串
         */
        StringBuilder sb = new StringBuilder();
        sb.append("#");
        for(int i = 0;i<N;i++){
            sb.append(s.charAt(i));
            sb.append("#");
        }

        int len = sb.length();
        int[] rad = new int[len];
        int center = -1;
        int right = 0;
        for(int i = 0;i<len;i++){
            int r = 1;
            /*
             * 确定最小半径
             */
            if(i<right){
               r = Math.min(right-i,rad[2*center-i]);
            }
            /*
             * 尝试扩展半径
             */
            while(i-r>=0&&i+r<len&&sb.charAt(i-r)==sb.charAt(i+r)){
                r++;
            }
            if(i+r>right){
                center = i;
                right = i+r;
            }
            rad[i] = r;
        }
        int max = 1;
        int index = -1;
        for(int k = 0;k<len;k++){
            if(rad[k]>max){
                max = rad[k];
                index= k;
            }
        }
        StringBuilder sc = new StringBuilder() ;
        for(int i = index-max+1;i<=index+max-1;i++){
            char c = sb.charAt(i);
            if(c!='#'){
                sc.append(sb.charAt(i));
            }
        }
        System.out.println(sc.toString());
        System.out.println(max-1);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值