最长回文子串中心扩散详解

p(? ,? )表示是否回文,并且 第一个参数是左端点,第二个是右端点
Si 表示字符串中位置i对应的字符

在这里插入图片描述

可以发现,所有的状态在转移的时候的可能性都是唯一的。也就是说,我们可以从每一种边界情况开始「扩展」,也可以得出所有的状态对应的答案。
注 :这里的边界不是指左右的边界,而是回文串的中间位置
P(i,j)才是字符串的左右边界,图中的状态转移链相当于从两边向中间倒推到中间的过程!!

边界情况即为子串长度为 1或 2(奇数或者偶数) 的情况。
就相当于 c a b a d 和 a b b c d
我们枚举每一种边界情况,并从对应的子串开始不断地向两边扩展。如果两边的字母相同,我们就可以继续扩展,例如从 P(i+1,j-1)P(i+1,j−1) 扩展到 P(i,j)P(i,j);
如果两边的字母不同,我们就可以停止扩展,因为在这之后的子串都不能是回文串了。

「边界情况」对应的子串实际上就是我们「扩展」出的回文串的「回文中心」。中心扩散算法的本质即为:我们枚举所有的「回文中心」并尝试「扩展」,直到无法扩展为止,此时的回文串长度即为此「回文中心」下的最长回文串长度。我们对所有的长度求出最大值,即可得到最终的答案。

注意看注释!!

public String longestPalindrome(String s) {
        int start = 0, end = 0;//用于标记最长回文子串的首尾下标
        for (int i = 0; i < s.length(); i++) {
            int len1 = expandAround(s, i, i);//这个是对应回文中心为奇数个的情况
            int len2 = expandAround(s, i, i + 1);//这个是对应回文中心为偶数个的情况
            int len = Math.max(len1, len2);//如果不是对应的参数,那长度肯定会变小,所以大的那个一定是我们要的当前回文中心对应的长度
            /**
             *  举个例子  :
             *
             *                c  a  b  b  d   i = 2 时调用 expandAround(s, i, i); ===》len1 = 1
             *       对应下标  0  1  2  3  4         但实际上应该是 2 (len2的结果)
             *
             *
             *               c  a  b  a  d    i = 2 时调用 expandAround(s, i, i + 1); ===》 len2 = 0
             *      对应下标  0  1  2  3  4          但实际上应该是 3 (len1的结果)
             */
            if (len > end - start) {
                start = i - (len - 1) / 2; // (len-1)/2就表示在长度为2的时候start还是在i的位置,
                end = i + len / 2;    // 而end在长度为2的时候还是要+1的
            }
        }
        return s.substring(start, end + 1);
    }

    //用于判断每个回文中心的最长回文子串的长度
    public int expandAround(String s, int l, int r) {
        while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) {
            l--;
            r++;
        }
        //当循环结束的时候,l和r所在的位置字符不相等,不在回文串的范围内,所以长度是下标差再 - 1
        return r - l - 1;
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值