马拉车算法

public class Solution {
    public int getLongestPalindrome (String str) {
        // 添加特殊字符,使得str为奇数长度的字符串,如aabb => #a#a#b#b#
        StringBuilder newStr = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            newStr.append('#');
            newStr.append(str.charAt(i));
        }
        newStr.append('#');
        str = new String(newStr);
        // dp数组,dp[i]用于记录以str[i]为中心的最大回文半径
        int[] dp = new int[str.length()];
        dp[0] = 1;
        // 维护一个区间[L, R],M是区间中点,该区间代表目前已知最靠右的回文串,dp与[L, R]互相帮助
        int L = 0, R = 0, M = 0;
        // 递推
        for (int i = 1; i < str.length(); i++) {
            // 当前位置落在[L, R]之外,最长回文串先认为是自身str[i]
            if (i > R) {
                dp[i] = 1;
            }
            // 落在[L, R]之内
            else {
                // 计算i关于M的对称点k,利用(i + k)/2 = M
                // 需注意对称的含义:在[L, R]的范围内,str[..k..]与str[..i..]完全一样
                int k = 2 * M - i;
                // k为中心的最长回文串不超过L,则dp[k]就是dp[i],否则只利用k不超出L的部分
                dp[i] = Math.min(dp[k], k - L + 1);
            }
            // 除了dp[i] = dp[k]的情况,其余的都是未探索完的情况,故而需进行探索
            // dp[i] = dp[k]虽然可以不用探索,但为了好写代码,一起进行探索,它探索一个字符就会自动停止
            while (i - dp[i] >= 0 && i + dp[i] < dp.length && str.charAt(i - dp[i]) == str.charAt(i + dp[i])) {
                dp[i]++;
            }
            // 更新区间[L, R]
            if (i + dp[i] - 1 > R) {
                L = i - dp[i] + 1;
                M = i;
                R = i + dp[i] - 1;
            }
        }
        // 搜索结果,由于填充了#,新的str的最大回文半径其实是旧的直径加1
        int res = 0;
        for (int i = 0; i < dp.length; i++) {
            if (dp[i] - 1 > res) {
                res = dp[i] - 1;
            }
        }
        return res;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值