最长回文子串的几种解法

这几天在刷leetcode,碰到了最长回文字串问题,网上查资料发现至少有4种解法,在学习完每种方法之后,写个博客总结下。参考了别人写的博客,可能会有些雷同。

参考资料:http://blog.csdn.net/kangroger/article/details/37742639

                 http://www.cnblogs.com/biyemyyhjob/archive/2012/10/04/2711527.html

最长回文子串问题:给出一个字符串str,求它的最长回文字串。回文字符串是指顺序和逆序是同一字符串的字符串。

解法1:暴力求解法

        根据习惯,首先想一个暴力解法,这个问题的暴力解法思想是这样:遍历每一个子串,判断是否是回文串,并维护一个最长回文起始地址和最大回文长度。求每一个子串时间复杂度O(N^2),判断子串是不是回文O(N),两者是相乘关系,所以时间复杂度为O(N^3)。代码如下:

	string longestPalindrome(string s) {
		int len = s.size();//字符串长度 
		if (len == 0) return " ";
		int maxlen = 0;//最长回文字符串长度  
		int start;//最长回文字符串起始地址  
		for (int i = 0; i<len; i++)//起始地址  
			for (int j = i; j < len; j++)//结束地址  
			{
				int tmp1, tmp2;
				for (tmp1 = i, tmp2 = j; tmp1 <= tmp2; tmp1++, tmp2--)//判断是不是回文  
				{
					if (s.at(tmp1) != s.at(tmp2))
						break;
				}
				if (tmp1 > tmp2 && j - i + 1 > maxlen)
				{
					maxlen = j - i + 1;
					start = i;
				}
			}
		return s.substr(start, maxlen);//求子串  
	}


解法2:动态规划法

回文字符串的以中心对称的子串也是回文,比如"abccba"是回文串,则"cc","bccb"也是回文。

可以用p[i][j]来表示以下标i开始,下标j结束的一个子串,则定义p[i][j]=1表示这个子串是回文串,p[i][j]=0不是回文串。可知对于所有i=0~length(str),

有p[i][i]=1,如果str[i]==str[i+1],则p[i][i+1]=1.这样就判断了长度为1和2的所有子串是不是回文串。更长长度的子串的判断,就可以根据其中心对称

子串是否是回文串以及两头的字符是否一样来判断了。空间复杂度O(N^2),时间复杂度O(N^2)。代码如下:

string longestPalindrome(string s) {
	const int length = s.size();
	int maxlength = 1;
	int start = 0;
	bool P[1000][1000] = { false };
	for (int i = 0; i<length; i++)//初始化准备  
	{
		P[i][i] = true;
		if (i<length - 1 && s.at(i) == s.at(i + 1))
		{
			P[i][i + 1] = true;
			start = i;                           //最后一个长度为2的回文串的起始下标
			maxlength = 2;
		}
	}
	for (int len = 3; len<=length; len++)//子串长度  
		for (int i = 0; i <= length - len; i++)//子串起始地址  
		{
			int j = i + len - 1;//子串结束地址  
			if (P[i + 1][j - 1] && s.at(i) == s.at(j))
			{
				P[i][j] = true;
				maxlength = len;
				start = i;
			}
		}
	return s.substr(start, maxlength);
}

解法3:中心扩展法

中心扩展就是把给定的字符串的每一个字母当做中心,向两边扩展,这样来找最长的子回文串。算法复杂度为O(N^2)。代码如下:

string longestPalindrome(string &s)
    {
        const int length = s.size();
	    int maxlength = 1;
	    int start = 0;
	    for (int i = 0; i < length; i++)
    	{
	    	int h = i - 1, k = i, j = i + 1;
	    	while (k >= 0 && j < length && s[k] == s[j])
	    	{
		    	if (maxlength <= j - k + 1)
		    	{
		    		maxlength = j - k + 1;
		    		start = k;
		    		k--;
		    		j++;
		    	}
		    	else
		    	{
		    		k--;
		    		j++;
		    	}
	    	}
	    	h = i - 1, k = i, j = i + 1;
	    	while (h >= 0 && j < length && s[h] == s[j])
	    	{
		    	if (maxlength <= j - h + 1)
		    	{
		    		maxlength = j - h + 1;
		    		start = h;
		    		h--;
		    		j++;
	    		}
	    		else
	    		{
		    		h--;
		    		j++;
		    	}
	    	}
    	}
	    return s.substr(start, maxlength);
    }

 

解法4:manacher法

参考http://www.cnblogs.com/biyeymyhjob/archive/2012/10/04/2711527.html  代码如下:

string longestPalindrome(string &s)
    {
        string str;
        str += "$#";
        for(int i = 0; i < s.size(); i++)
        {
            str += s[i];
            str += "#";
        }
        int *p = new int[str.size() + 1];
        memset(p, 0, sizeof(p));

        int mx = 0, id = 0;
        for(int i = 1; i <=  str.size(); i++)
        {
            if(mx > i)
            {
                p[i] = (p[2*id - i] < (mx - i) ? p[2*id - i] : (mx - i));
            }
            else
            {
                p[i] = 1;
            }

            while(str[i - p[i]] == str[i + p[i]])
                p[i]++;

            if(i + p[i] > mx)
            {
                mx = i + p[i];
                id = i;
            }

        }
        int max = 0, ii;
        for(int i = 1; i < str.size(); i++)
        {
            if(p[i] > max)
            {
                ii = i;
                max = p[i];
            }
        }

        max--;

        int start = ii - max ;
        int end = ii + max;
        char buf[1000];
        memset(buf,'\0',1000);
        int k=0;
        for(int i = start; i <= end; i++)
        {
            if(str[i] != '#')
            {
                buf[k++] = str[i];
            }
        }
        delete  p;
        return buf;
    }






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用中的代码展示了一种求解最长回文子串的暴力解法,即遍历字符串的所有子串,判断是否为回文,并记录最长的回文子串。但是这种方法的时间复杂度较高,不适用于较长的字符串。 Python 中有一种更优化的方法来求解最长回文子串,即中心扩展法。该方法的基本思想是从字符串的每个字符和每两个相邻字符之间展开,向两边扩展判断是否为回文子串。具体步骤如下: 1. 定义一个函数 expandAroundCenter,用于判断以某个中心点向两边扩展的回文子串的长度。 2. 遍历字符串,将每个字符和其相邻字符都作为中心点进行扩展,计算得到回文子串的最大长度。 3. 根据最大长度和中心点位置,确定最长回文子串的起始位置和结束位置。 4. 返回最长回文子串。 下面是基于中心扩展法的 Python 代码示例: ``` class Solution: def longestPalindrome(self, s): if len(s) < 2: return s start, end = 0, 0 for i in range(len(s)): len1 = self.expandAroundCenter(s, i, i) # 以一个字符为中心向两边扩展 len2 = self.expandAroundCenter(s, i, i+1) # 以相邻两个字符为中心向两边扩展 max_len = max(len1, len2) if max_len > end - start: start = i - (max_len - 1) // 2 end = i + max_len // 2 return s[start:end+1] def expandAroundCenter(self, s, left, right): while left >= 0 and right < len(s) and s[left] == s[right]: left -= 1 right += 1 return right - left - 1 s = "ac" S = Solution() result = S.longestPalindrome(s) print(result) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值