最长回文串——manacher算法java实现

最长回文串是一个很好玩的话题,给出一个无序的不定长的字符序列,如何知道里面的最长回文串呢?

manacher算法的思想是

1 把偶数、奇数长的字符序列变成奇数长度

2 创建一个与字符串等长的数组,用来记录字符序列相应位置上字符的最长回文半径,半径为1时默认为字符本身。

3 然后以每个字符为中轴遍历字符序列,之后求数组的最大值即为最大的半径,即为最长的回文半径。

最长回文串便迎刃而解了。

package com.lgy;


public class Manacher {
    public static void main(String[] args) {
        String s = "acbahkafojlnavnufnavkvnv";
        doManacher(s);
    }

    public static void doManacher(String s) {
        //在字符串两头和质检添加特殊字符转成奇数长度,原理:奇数+奇数+1=奇数,偶数+偶数+1=奇数。
        StringBuffer sb = new StringBuffer();
        sb.append("#");
        for (int i = 0; i < s.length(); i++) {
            sb = sb.append(s.substring(i, i + 1)).append("#");
        }
        s = sb.toString();

//		以每个字符为轴求最长回文串半径,其中半径=1表示字符本身。
        int[] p = new int[s.length()];
        int left, right = 0;
        for (int i = 0; i < s.length(); i++) {
            int len = 1;
            for (left = i - 1, right = i + 1; left >= 0 && right <= (2 * i) && right < s.length(); left--, right++) {
                if (s.charAt(left) == s.charAt(right)) {
                    len = len + 1;
                    continue;//如果匹配成功就继续
                } else {
                    break;//不成功就跳出循环
                }
            }
            p[i] = len;
        }//end wai for

        //求最大的p[i]值
        int pos, maxValuePos = 0;
        for (int i = 0; i < p.length - 1; i++) {
            pos = i;
            for (int j = i + 1; j < p.length; j++) {
                if (p[i] < p[j]) {
                    pos = j;
                    int tep = p[i];
                    p[i] = p[pos];
                    p[pos] = tep;
                }
                if (i == 0)
                    maxValuePos = pos;
            }
        }
        //求得的回文串一定是奇数长度
        int realLen = ((p[0] * 2 - 1) - 1) / 2;//最长回文串的长度,去掉其他字符
        System.out.println("最长的回文串长度为:" + realLen);


//求最长回文串内容
        String huiwen;
        StringBuffer realHuiwen = new StringBuffer();
        if (realLen == 1) {
            System.out.println("最长回文串为:" + s.charAt(maxValuePos));
        } else {
//              截出来
            huiwen = s.substring((maxValuePos + 1 - p[0]), maxValuePos + p[0]);
//             去掉辅助字符
            for (int j = 0; j < huiwen.length(); j++) {
                if (j % 2 != 0)
                    realHuiwen = realHuiwen.append(huiwen.charAt(j));
            }
            System.out.println("最长回文串为:" + realHuiwen.toString());
        }

    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值