Manacher

找到最长回文子串的问题

暴力解

从中间往两边扩
奇数回文,偶数回文不好解决
每个字符两边加## 11311 -> #1#1#3#1#1# ,各字符的最大回文长度/2
时间复杂度O(N^2)

manacher解 时间复杂度O(N)

基础概念

回文半径直径数组
最右回文右边界:所有回文半径中最靠右的位置
在这里插入图片描述
回文右边界的中心:
在这里插入图片描述
可能性1:i不在回文右边界内,暴力扩

在回文右边界内,找到右边界的中心C,并确定i的对称位置,
可能性2:
在这里插入图片描述
可能性3:
在这里插入图片描述
在这里插入图片描述
可能性4;

在这里插入图片描述

/**
 * Created by huajianJin on 2019/10/17.
 * 最长回文子串O(N)
 */
public class Manacher {

    //字符两边加#,便于求解回文个数是奇数个的子串,所求回文长度/2
    private static char[] getManacherString(String str) {
        char res[] = new char[str.length() * 2 + 1]; // 长度是2倍加1,每个元素左边都放一个#,最后一个元素右边放一个#
        char[] chs = str.toCharArray();
        int index = 0;
        for (int i = 0; i < res.length; i++) {
            res[i] = (i & 1) == 0 ? '#' : chs[index++];
        }
        return res;
    }

    private static int maxLcpsLength(String str) {
        // 初始化数据
        char[] chs = getManacherString(str);
        int centre = -1;
        int rightBound = -1;
        int[] cpsCnt = new int[chs.length]; // 记录每个位置的回文子串长度
        int maxLength = 0, maxCentre = -1;
        for (int pos = 0; pos < chs.length; pos++) {
            // 根据已求得回文长度判断pos的最长回文长度
            cpsCnt[pos] = rightBound > pos ? Math.min(rightBound - pos, cpsCnt[2 * centre - pos]) : 1;
            // 继续扩展pos位置的回文串
            while (pos + cpsCnt[pos] < chs.length && pos - cpsCnt[pos] > -1) {
                if (chs[pos + cpsCnt[pos]] == chs[pos - cpsCnt[pos]]) {
                    cpsCnt[pos]++;
                } else
                    break;
            }
            // 若pos的回文长度大于当前最大右边界,更新右边界
            if (pos + cpsCnt[pos] > rightBound) {
                rightBound = pos + cpsCnt[pos];
                centre = pos; // 更新当前中心
            }
            // 若pos的回文长度大于之前求得最大回文长度,更新回文长度
            if (cpsCnt[pos] > maxLength) {
                maxLength = cpsCnt[pos];
                maxCentre = pos;
            }
        }
        maxLength--;
//        String res = new String(chs).substring(maxCentre - maxLength, maxCentre + maxLength + 1).replace("#", "");
//        System.out.println(res);
        return maxLength;
    }

    public static void main(String[] args) {
        String str = "abc1234321cab";
        System.out.println(new String(getManacherString(str)));
        int res = maxLcpsLength(str);
        System.out.println(res);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值