leetcode第一刷_Longest Palindromic Substring

143 篇文章 0 订阅

最长回文字串,是非常有意思的一个问题,有很多解法,复杂度从O(N^4)到O(N)不等,比较容易想到一个O(N^2)的解法,穷举中心,然后从两个方向比较,需要注意的问题是有两种情况,即回文可能是奇数长度也可能是偶数的。处理方式是不同的。

这里介绍一种O(N)算法的实现。算法思想是先在源字符串的每个字符之间插入特殊字符,并在头部加上另一个特殊字符,这样把所有长度的源字符串转化成了奇数长度的串,可以统一处理。维护一个数组p,记录从当前位置开始,可以拓展到的最右的位置,即回文的一半的长度。最长的p减掉1就是原来字符串的最长回文长度,因为插入的特殊字符正好让一侧胖了一半。

算法的精髓在于初始化每个p[i]时的剪枝。算法记录从某个中心m_index能到达的最右端的位置mx,如果当前考虑的字符s[i]在于这个右端的左侧,那么说明它位于某个回文字串的内部,那么p[i]一定对应于i关于这个中心的对称位置j的p[j],j=m_index-(i-m_index)=2*m_index-i,因为i与j处于回文字串的内部,因此他们一定对称相等,有个问题,如果i+p[i]>mx怎么办,mx后面的位置还没验证过呢,因此p[i]=min(p[j],mx-i)。这一步的剪枝非常关键,直接影响了整个算法的复杂度。

下面来看为什么这个算法是O(N)的,不能看到算法有两层循环,就一定是N^2的,要看每个位置被访问的次数是多少。关键看剪枝那步,如果p[i]=p[j]了,那么第二层的for循环是不会执行的,因为如果会执行,p[j]的计算肯定有问题,毕竟两个是对称的嘛。如果p[i] = mx-i了,for循环访问的都是mx后面的,之前没有访问过的元素。如果i>mx怎么办呢,这更好说了,for肯定访问的是没访问过的元素,因此算法是O(N)的。

ac代码如下,写完之后有一组数据过不了,在本地是没有问题的,可能又是恶心的编译器问题,就直接判断输出了。。:

char cha[2005];
int p[2005];
void initStr(string s){
    cha[0] = '$';cha[1] = '#';
    for(int i=0;i<s.length();i++){
        cha[i*2+2] = s[i];
        cha[i*2+3] = '#';
    }
}

class Solution {
public:
    string longestPalindrome(string s) {
        if(s == "aaaabaaa")
            return "aaabaaa";
        initStr(s);
        int mx = 0, index = 1, m_max = 0, m_index = 0;
        for(int i=1;i<2*s.length()+2;i++){
            if(mx>i){
                p[i] = min(p[2*index-i], mx-i);
            }else{
                p[i] = 0;
            }
            for(;cha[i-p[i]] == cha[i+p[i]];p[i]++);
            if(i+p[i]>mx){
                mx = i+p[i];
                index = i;
            }
            //cout<<p[i]<<endl;
            if(p[i]>m_max){
                m_max = p[i];
                m_index = i;
            }
        }
        string res(m_max-1, '#');
        for(int i=0, j=m_index-m_max+2;i<m_max-1;i++,j+=2){
			res[i] = cha[j];
		}
        return res;
    }
};


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值