Manacher算法--O(n)内求回文子串

昨天做了leetcode里的     Longest Palindromic Substring ,一开始用动态规划O(N^2),不管怎么改都超时了。。。于是在大神的帮助下,找到了传说中的Manacher算法,居然能在O(n)内求出来,瞬间给跪了。

本屌认为,这个算法主要是充分的利用了以前的匹配的结果,来起到了降低时间复杂度的作用,这点跟KMP算是有点类似。在预处理时有个小技巧就是将第0,1为设为"$#",后面每隔一位加一个“#”,这样既能够防止数组越界问题又能够,避免奇数和偶数的讨论。如
aaaa 就变成 $#a#a#a#a#

这是核心部分代码:

void Manacher(int n)
{
    int mx=0;
    int id;
    p[0]=0;
    for(int i=1;i<n;i++)
    {
        p[i]=1;
        if(mx>i)
        {
            p[i]=min(p[2*id-i],mx-i);
        }
        while(str[i-p[i]]==str[i+p[i]]) p[i]++;
        if(i+p[i]>mx)
        {
            id=i;
            mx=i+p[i];
        }
    }
}

P[i]记录的是以字符str[i]为中心的最长回文串的半径。且这里有一个很好的性质,P[i]-1就是该回文子串在原串中的长度(包括‘#’)

举个例子:

原串:    w aa bwsw f d

新串:  
# w# a # a # b# w # s # w # f # d #

辅助数组P:  1
2 1 2 3 2 1 2 1 2 1 4 1 2 1 2 1 2 1

接下来就是关键部分了,如何运用前面的结果

        if(mx>i)
        {
            p[i]=min(p[2*id-i],mx-i);
        }

接下来就借用下大神的图了

有两种情况

下附上某大牛的地址:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824

这个是题目链接:https://oj.leetcode.com/problems/longest-palindromic-substring/

Longest Palindromic Substring

Total Accepted: 11893 Total
Submissions: 58709My Submissions

Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest
palindromic substring.

Have you been asked this question in an interview?

这个是AC的:

class Solution {
private:
	string stmp;
	string init(string s)
	{
		string ret="$";
		for(int i=0;i<s.size();i++)
		{
			ret+="#"+s.substr(i,1);
		}
		ret+="#";
		return ret;
	}
	void Manacher(int len,string str,int *p)
	{
		int mx=0;
		int id;
		p[0]=0;
		for(int i=1;i<len;i++)
		{

			p[i]=1;
			if(mx>i)
			{
				p[i]=min(p[2*id-i],mx-i);
			}
			while(str[i-p[i]]==str[i+p[i]]) p[i]++;
			if(i+p[i]>mx)
			{
				id=i;
				mx=i+p[i];
			}
		}
	}
public:
    string longestPalindrome(string s)
    {
        string str=init(s);
        int *p=new int[str.size()];
        Manacher(str.size(),str,p);
        int ans=0,index=0;
        for(int i=1;i<str.size();i++)
        {
        	if(p[i]>ans)
        	{
        		ans=p[i];
        		index=i;
        	}
        }
        delete []p;
        return s.substr((index-ans)/2,ans-1);
    }
};

这个是动态规划的,跟网上的大同小异,不过超时了:

class Solution {
public:
    string longestPalindrome(string s)
    {
        int m=1,beg=0,end=0;
        int len=s.size();
        bool flag[len][len];
        for(int i=0;i<len;i++)
        	for(int j=0;j<len;j++)
        	{
        		if(i>=j) flag[i][j]=true;
        		else flag[i][j]=false;
        	}
        for(int j=1;j<len;j++)
        	for(int i=0;i<j;i++)
        	{
        		if(s[i]==s[j])
        		{
        			flag[i][j]=flag[i+1][j-1];
        			if(flag[i][j]&&j-i+1>m)
        			{
        				beg=i;
        				end=j;
        				m=j-i+1;
        			}
        		}
        		else
        			flag[i][j]=false;
        	}
        return s.substr(beg,m);
    }
};

Manacher算法--O(n)内求回文子串,布布扣,bubuko.com

时间: 2024-11-05 09:27:19

Manacher算法--O(n)内求回文子串的相关文章

数据结构--Manacher算法(最长回文子串)

在字符串中求出其最长回文子串 可能是奇回文也可能是偶回文,要考虑全面 暴力解法:(因为存在奇回文和偶回文的问题,所以不好找,有一个技巧,就是想字符串中每个字符之间添加一个符号(任意符号,也可以是字符串中的符号),然后在每个位置向两端开始扩充) 答案就是最大值/2 Manacher算法: 字符串中每个字符串之间也要加上一个字符 回文直径:从某个位置开始向两边扩的最大长度 1. 回文半径数组:arr[],以每个位置为中心能扩出来的回文半径的长度 2. 最右回文右边界R:所有回文半径中,最靠右的位置

Manacher算法解决最长回文子串长度问题

马拉车(Manacher)算法(具体算法流程看这个哥们的:https://blog.csdn.net/qq_35065720/article/details/104205920): 算法解决:在一个字符串中找到最长的回文字符串. 实现策略: 以每个位置作为中心,向两边扩展,可以确定奇回文,但是偶回文无法这样做. 解决方法:在字符串中间及两边插入某种字符,此时可以按照这种方法进行扩展.此时无论奇回文还是偶回文都可以找到. 例如11211,此时添加任意字符在两边#1#1#2#1#1#此时均可以进行回

Manacher&#39;s algorithm: 最长回文子串算法

Manacher 算法是时间.空间复杂度都为 O(n) 的解决 Longest palindromic substring(最长回文子串)的算法.回文串是中心对称的串,比如 'abcba'.'abccba'.那么最长回文子串顾名思义,就是求一个序列中的子串中,最长的回文串.本文最后用 Python 实现算法,为了方便理解,文中出现的数学式也采用 py 的记法. 在 leetcode 上用时间复杂度 O(n**2).空间复杂度 O(1) 的算法做完这道题之后,搜了一下发现有 O(n) 的算法.可惜

[算法]manachar最长回文子串

现给定一个已知的字符串str[],现在想要在O(n)的时间复杂度之内求出一个最长的回文子字符串(正着和倒着顺序读一致). Manacher最早发现了可以用O(n)的时间复杂度来解决该问题,所以这种方法称之为Manacher算法. #include <iostream> using namespace std; int min(int a, int b){ return a > b ? b : a; } char* preproccess(char* src, char* des){ in

【算法】最长回文子串 longest palindrome substring

对于字符串S, 要找到它最长的回文子串,能想到的最暴力方法,应该是对于每个元素i-th都向左向右对称搜索,最后用一个数组span 记录下相对应元素i-th为中心的回文子串长度. 那么问题来了: 1. 这样的方法,对于奇回文子串和偶回文子串的处理不一样,比如所"acbca" 和"acbbca" 2. 计算冗余,e.g. "sscssabcccchccccba"中, 自左向右遍历计算的话,会发现, "abcccchccccba"是

算法题之最大回文子串

题目描述对于一个字符串,请设计一个高效算法,计算其中最长回文子串的长度.给定字符串A以及它的长度n,请返回最长回文子串的长度. 测试样例:"abc1234321ab",12 返回:7 1. 普通轮询(运行时间80ms): class Palindrome { public: bool isHuiWen(string A, int n){ int k = n / 2; for (int i = 0; i < k; ++i) { if (A.at(i) != A.at(n - 1 -

manacher算法求最长回文子序列

一:背景 给定一个字符串,求出其最长回文子串.例如: s="abcd",最长回文长度为 1: s="ababa",最长回文长度为 5: s="abccb",最长回文长度为 4,即bccb. 以上问题的传统思路大概是,遍历每一个字符,以该字符为中心向两边查找.其时间复杂度为O(n^2),效率很差. 1975年,一个叫Manacher的人发明了一个算法,Manacher算法(中文名:马拉车算法),该算法可以把时间复杂度提升到O(n).下面来看看马拉车

【Manacher算法】最长子回文串

[Manacher算法] 这个算法用来找出一个字符串中最长的回文子字符串. 如果采取暴力解最长回文子字符串问题,大概可以有两种思路:1. 遍历出所有子字符串找其中最长的回文 2. 从每个字符作为中心,向两边扩散看是否回文. 第二种比第一种稍微高明一点,但是总体的复杂度还是O(n^2)的. 而Manacher算法可以做到O(n)时间复杂度,O(n)空间复杂度. ■ 思路&描述 回文字符串有一个比较麻烦的地方,就是回文串有偶回文和奇回文两种,分别举例ABBA和ABCBA.这种区别可能要让我们在程序中

(算法)最长回文子串

题目: 求一个字符串的最长回文子串 思路: 1.暴力枚举 最容易想到的就是暴力破解,列举每一个子串,然后根据回文的定义判断是不是回文,找到最长的那个. 求每一个子串的时间复杂度为O(N^2),判断子串是不是回文的时间复杂度为O(N),所以时间复杂度为O(N^3). 2.动态规划 回文字符串的子串也是回文,比如P[i,j](表示以i开始以j结束的子串)是回文字符串,那么P[i+1,j-1]也是回文字符串.这样最长回文子串就能分解成一系列子问题了. 这样需要额外的空间是O(N^2),时间复杂度也是O