给定字符串S,求它的最长回文子串。假设S的最长长度为1000,并且仅有唯一的最长回文子串。
一、暴力法( Brute Force)
最简便,但同时时间复杂度也是最高的肯定是暴力解法,就是遍历字符串的“所有子串”,并判断每个子串是否为对称回文。因为字符串所有子串的复杂度为$O(n^2)$,在判断回文,总体的复杂度达到$O(n^3)$。
复杂度:时间 $O(n^3) $空间 $O(1)$
可以做一些简单的优化:从最长的子串开始遍历,一旦找到一个回文,就终止迭代。
- 判断回文采用收缩法,从最外一对字符往中心推进。
|
|
二、动态规划
根据回文的特性,一个大回文按比例缩小后的字符串也必定是回文,比如ABCCBA,那BCCB肯定也是回文。所以我们可以根据动态规划的两个特点:第一大问题拆解为小问题,第二重复利用之前的计算结果,来解答这道题。那如何划分小问题呢,我们可以先把所有长度最短为1的子字符串计算出来,根据起始位置从左向右,这些必定是回文。然后计算所有长度为2的子字符串,再根据起始位置从左向右。到长度为3的时候,我们就可以利用上次的计算结果:如果中心对称的短字符串不是回文,那长字符串也不是,如果短字符串是回文,那就要看长字符串两头是否一样。这样,一直到长度最大的子字符串,我们就把整个字符串集穷举完了,但是由于使用动态规划,使计算时间从$O(N^3)$减少到$O(n^2)$。
- 复杂度:时间 $O(n^2) $空间 $O(n^2)$
|
|
三、中心扩散法
动态规划虽然优化了时间,但也浪费了空间。实际上我们并不需要一直存储所有子字符串的回文情况,我们需要知道的只是中心对称的较小一层是否是回文。所以如果我们从小到大连续以某点为个中心的所有子字符串进行计算,就能省略这个空间。 这种解法中,外层循环遍历的是子字符串的中心点,内层循环则是从中心扩散,一旦不是回文就不再计算其他以此为中心的较大的字符串。由于中心对称有两种情况,一是奇数个字母以某个字母对称,而是偶数个字母以两个字母中间为对称,所以我们要分别计算这两种对称情况。
- 复杂度:时间 O(n^2) 空间 O(1)
|
|
四、马拉车算法
|
|