码迷,mamicode.com
首页 > 其他好文 > 详细

第五题:Longest Palindromic Substring

时间:2015-02-12 00:50:18      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:题目链接


题意:找最长回文子串(注意不是回文序列,不一样,字串需要连续,序列不需要连续)


方法一:

这一题说实话,只想到最“土”的方法,就是找到所有的可能的串,然后得到最长的回文串。

需要注意:回文串有奇数和偶数之分,所以以当前这个点为中心,存在两种:这个点是最中间的点;这个点和之前一个点需要进行比较。

看代码如下:

class Solution {
public:
    string longestPalindrome(string s) {
        int max_len = 0, n = s.length(), len = 0, i, start = 0;
        int low, high;

        // 当前点参与回文比较
        //
        for (i = 0; i < n; ++i){
            low = i - 1;
            high = i;
            len = 0;
            while (low >= 0 && high < n && s[low] == s[high]){
                --low;
                ++high;
                len += 2;
            }
            if (max_len < len){
                start = low + 1;
                max_len = len;
            }
        }

        // 当前点不参与比较
        //
        for (i = 0; i < n; ++i){
            low = i - 1;
            high = i + 1;
            len = 1;
            while (low >= 0 && high < n && s[low] == s[high]){
                --low;
                ++high;
                len += 2;
            }
            if (max_len < len){
                start = low + 1;
                max_len = len;
            }
        }

        return s.substr(start, max_len);
    }
};

方法二:(网上学习得到)

这一题还有一个很有“技术”的算法,这个真的挺不错的!号称Manacher’s Algorithm,时间复杂度是O(n)。

1、首先这个算法建立在“奇数”数量字符字符串中才好使,所以第一步我们需要将原始的字符串改造成奇数个数,方法是,在所有字符之间个收尾都插入一个#字符,那么原来奇数的还是奇数,原来偶数的也是奇数个数了,例如:

aabb ==> #a#a#b#b#

aba ===> #a#b#a#


2、然后我们需要一个数组P记录以i字符为中心,向两边扩展最长的回文串。这个算法的优势在于什么呢?其实就是减少了一些位置处的回文串的计算。他借助的是回文串的对称性。例如:现在有一个回文串:

a  b  a  b  a  b  a  b  a 

1  3  5  1  9  1  ?

根据前面的位置计算我们知道现在这个串是一个回文串,现在遍历到?位置,那么我们需要计算以?为中心(即a)的最长回文字符串是多少,一般情况我们是从?向左和向右进行遍历处理。但是存在一种情况是,如果前面(本例中中就是中间的a)是一个很大的回文字符串,?在这个串内,那么这个?可以不用计算就能得到结果,因为是和左边自己对称的a的值是一样的即5!所以不用遍历就知道答案是5!

a  b  a  b  a  b  a  b  a 


所以这个算法其实就是钻了这个空子~~~

最终我们呢找到P数组中最大的值,就是所谓的以i为中心能扩张最大的回文串就是我们需要的结果。


下面具体说说本算法:

对于下面例子:

T =  #  a  #  b  #  a  #  a  #  b  #  a  # P =  0  1  0  3  0  1  6  1  0  3  0  1  0

首先我们呢需要知道,以最大值6为中心,这个值其实就是最大回文串长度,因为加入了相等长度的#,那么其实12/2=6就是咯~

那么P到底是怎么计算的呢?

 

我们看一个字符串:S = “babcbabcbaccba”.

如果现在我们遍历了的情况是下图:

技术分享

(图片来自互联网)

C代表的是现在的中心点,L和R分别是以这个点为中心点扩展到两边最远的长度边界!

现在我们需要知道?处是什么答案,我们根据上面的理解,显然是以C为中心和?对称位置的值即9号位置,所以?=1。同理我们知道后面的# 和c处也是和前面一样对称的值!但是到了i=15处!!!有什么问题,看看:

技术分享

(图片来自互联网)

可以知道对称位置7处,值是7,意思是以7为中心可以向两边扩展长度7。但是我们知道15处,不能扩展到7,只能扩展到5就结束了!这个是个关键处理!原因是什么呢?是由于i=15位置处如果想达到扩展7,必须要超过右边界R!!!而R之外的情况我们当前还是未知的!所以没有办法直接赋值对称位置较大的值7!现在只能赋值5!如果想扩展到7,只有向外扩展R,然后和左边进行比较!所以

P[i] = min(R-i, P[i对称值])

 

同时需要注意,如果R被扩展了,那么就需要更新,同时中心点C也被更新咯!

 

3、那么现在总结一下这个算法的步骤

1)、如果当前位置在之前的那个中心范围内,即如果i<R,那么就可以使用对称性做,P[i] = min(R-i, P[对称值]);如果不在这个范围内,那么就是0为初值!!!

2)、然后看看能不能向当前已有的范围P[i]外面扩展,如果可以,那么++P[i]

3)、最后需要判断当前i为中心的右边界是不是已经超越之前的边界了,如果是,则需要更新右边界R和中心点C

4)、最后,找到最大的P[i]OK

 

下面看代码:

class Solution {
public:
    string longestPalindrome(string s) {
        // 首先我们处理s字符串
		// 
		string str = "^";
		int i = 0, n = s.length();
		while (i < n) {
			str += "#";
			str += s[i++];
		}
		// 结尾
		// 
		str += "#$";

		// 下面正式处理
		// 
		n = str.length();
		int *P = (int *)malloc(n*sizeof(int));
		memset(P, 0, n*sizeof(int));
		int C = 0, R = 0;
		
		for (i = 1; i < n - 1; ++i) {
			// 第一步,看看能不能取对称位置值
			// 对称位置:C-(i-C)=2-i
			//
			int symmetry_i = 2*C - i;	

			// 看看i在不在当前中心的回文范围内!
			// 如果在那么取min(R-i, P[symmetry_i]),
			// 否则初始化为0
			// 
			P[i] = R > i ? min(R-i, P[symmetry_i]) : 0;

			// 下面看看以i为中心,在P[i]之外还能不能扩展
			// 
			while (str[i + P[i] + 1] == str[i - P[i] - 1])
				++P[i];

			// 最后看看扩展的范围是不是超过R边界了
			// 如果超过了,需要处理C和R
			// 
			if (P[i] + i > R){
				R = P[i] + i;
				C = i;
			}
		}

		// 找到最大的P[i]值
		// 
		int idx = 0;
		int max_len = 0;
		for (i = 0; i < n; ++i) {
			if (P[i] > max_len){
				idx = i;
				max_len = P[i];
			}
		}
		
		// 返回这个找到的字符串,注意使用的是原始字符串s哦!
		// 
		return s.substr((idx - max_len - 1)/2, max_len);
    }
};












第五题:Longest Palindromic Substring

标签:

原文地址:http://blog.csdn.net/shanshanpt/article/details/43700613

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!