博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第五题:Longest Palindromic Substring
阅读量:4054 次
发布时间:2019-05-25

本文共 3578 字,大约阅读时间需要 11 分钟。

题目链接:

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

方法一:

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

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

看代码如下:

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);    }};

你可能感兴趣的文章
计算机网络复习要点
查看>>
Variable property attributes or Modifiers in iOS
查看>>
NSNotificationCenter 用法总结
查看>>
C primer plus 基础总结(一)
查看>>
剑指offer算法题分析与整理(三)
查看>>
mint/ubuntu安装搜狗输入法
查看>>
C++动态申请数组和参数传递问题
查看>>
opencv学习——在MFC中读取和显示图像
查看>>
JVM并发机制探讨—内存模型、内存可见性和指令重排序
查看>>
nginx+tomcat+memcached (msm)实现 session同步复制
查看>>
c++模板与泛型编程
查看>>
WAV文件解析
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
WPF UI&控件免费开源库
查看>>
QT打开项目提示no valid settings file could be found
查看>>
Win10+VS+ESP32环境搭建
查看>>
android 代码实现圆角
查看>>
flutter-解析json
查看>>
android中shader的使用
查看>>
java LinkedList与ArrayList迭代器遍历和for遍历对比
查看>>