[译+改]最长回文子串(Longest Palindromic Substring) Part II

今天在做leetCode的https://leetcode.com/problems/palindromic-substrings/description/这道题时遇到了一个很有趣的算法,Manacher’s Algorithm (俗称马拉车算法,哈哈),看leetCode的解法时有些细节没有弄懂,看下面这篇文章得到了解答,感谢作者!!!他是用C++实现的,我在结尾附上了我自己写的Java实现,有详尽的代码注释。
文章链接如下:
http://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Part-II.html
有兴趣的朋友可以去看看,很有意思的算法。

以下是我的JAVA实现

//有一点值得说明一下,T的首尾字符(不允许设置为#),作者只是简单的提了一下,边界检查,我想了一下,我们实际上遍历是从i = 1到 len - 2,略去了首尾字符,而这两个字符的作用就在于,让我们在i = 1和i = len - 2的时候T[i - p[i]  - 1]和对应的T[i + p[i] + 1]不会越界(这也是为什么不允许设置为#的原因)。
class Solution {
    public int countSubstrings(String s) {
        int len = s.length() * 2 + 3;
        char[] T = new char[len];
        T[0] = '@';
        T[1] = '#';
        int t = 2;
        for(char c : s.toCharArray()){
            T[t++] = c;
            T[t++] = '#';
        }
        T[t] = '$';
        int[] p = new int[len];
        //中心,中心右边界
        int C = 0,R = 0;
        for(int i = 1;i < len - 1;i++){
            //与i对称的i'
            int mirror = C - (i - C);
            //i与右边界的距离
            int diff = R - i;
            //若i落在中心与右边界之间
            if(diff >= 0){
                //若p[mirror] < diff,说明可以使用对称的特性,p[i] = p[i'],否则将p[i]赋值为diff,之后须要遍历求得p[i]
                if(p[mirror] < diff){
                    p[i] = p[mirror];
                }else{
                    p[i] = diff;
                    while(T[i + p[i] + 1] == T[i - p[i] - 1])p[i]++;
                    C = i;
                    R = i + p[i];
                }
            }else{
                //若落在右边界之外,则计算p[i],更新中心和右边界
                p[i] = 0;
                while(T[i + p[i] + 1] == T[i - p[i] - 1]) p[i]++;
                C = i;
                R = i + p[i];
            }
        }
        int sum = 0;
        //利用p数组求得sum,公式可以这样理解,如果p[i]为5,那么可以得到长度分别为1,3,5的回文子串,也就是(5 + 1) / 2 = 3
        for(int i : p) sum += (1 + i) / 2;
        return sum;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值