Longest Palindromic Substring解题心得
原题描述:https://leetcode.com/problems/longest-palindromic-substring/description/
第一种思路
以每个字母为中心向两端进行匹配
对于最长回文子串问题,我想到的第一种解题思路就是顺序遍历字符串s,以回文子串的中心为目标匹配搜索回文子串
设置中心下标i,设定left,right哨兵,以当前s[i]为中心进行向两端的字母匹配,同时每次比较并记录最大回文子串半径maxR(即子串长度的一半),以及子串的左右位置left,right
- 坑点:仔细思考下,这样的思路缺少了对偶数长度回文子串的搜索,所以可以进行如下改进
- 使i遍历s.size()*2次,每当i遍历到偶数则,以s[i/2]为中心进行回文匹配;当i为奇数时,则设定left=i/2,right=(i+1)/2,从而双向扩张搜索匹配的回文
- 为s间隔插入特殊字符,如插入’$‘ 或者‘ ’,匹配得到的最大半径不是实际最长回文子串的半径,而是中间含有特殊字符的字符串,需要另外过滤得到真实值
复杂度分析
- 时间复杂度
- 纠正后的算法,设定k为最长子串的半径,n为字符串长度,则时间复杂度为 O(nk) ,最差情况下为 O(n2)
- 空间复杂度
- 由于算法只是对字符串进行遍历,对于第一种纠正方法,需要n的空间,第二种则需要2n的空间,于是我们可以得出空间复杂度为 O(n)
第二种思路
利用回文的性质减少重复性搜索
分析发现回文拥有一种特质,即左右的对称性
所以我们以第一种算法的思路为基础进行改良,当我们以i为中心向两边搜索时,已知左边的字母的回文半径,在左边位置left下,回文半径为R[left],
右边字母由于对称性可以知道,只要以left为中心的回文在以flag为中心的回文范围内,即left-(flag-R[flag])>R[left] 或者 (flag+R[flag])-right>R[right]则可以断定R[right]=R[left](注:具体实现需要根据R[flag]的定义形式,判断临界值情况)
if (R[j]>=right-i){
flag=i;
right++;
left=2*i-right;
break;
}
else {
R[i]=R[j];
}
这样子,当当前flag位置的R[flag]求到后,再对flag为中心的回文子串S[flag]进行检查,同时更新回文右边的R[i],当出现半径长度超过以flag为中心字符串的范围时,更新flag到当前位置flag=right;,进入下一层循环,则flag到right之间的循环可以省略
- 坑点:千万不要忘记!!!flag更新后,更新right和left时不要直接让right=flag一样的位置;而应该当R[j]超出范围,则right只向右移动一位,同时更新left,保持对称性,这样可以节省很多不必要的重复搜索
代码实现如下:
复杂度分析
对于这种算法的时间复杂度分析,本人不才,想法不是特别清晰,意识里猜测是O(n)的时间,具体证明方法未想到