★leetcode05_Longest Palindromic Substring
来源:互联网 发布:凸优化 中文版 pdf 编辑:程序博客网 时间:2024/05/17 23:01
一.问题描述
Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
回文字符串,eg:
“abba”或“abcba”
二.编写代码
回文字符串是以最中间字符为中心向两边对称的,因此考虑如下算法:对每个字符串,寻找以其为中心的最长回文子串。该算法时间复杂度为O(N^2)。算法实现中需要注意的是两种回文情况要分别考虑到。
代码如下:
class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ # 长度 len_s = len(s) # 两个指针初始化 # i=0 # j=len_s-1 # 初始化最长回文字符串机器长度 max_str = s[0] max_str_len = 1 # 奇数长度的回文串 for i in range(0, len_s - 1): # 对每个i,寻找以它为中心的最长回文串 len1 = 1 j = i + 1 i = i - 1 while i >= 0 and j < len_s: if s[i] == s[j]: len1 = len1 + 2 i = i - 1 j = j + 1 else: break if len1 > max_str_len: max_str_len = len1 max_str = s[i + 1:j] # 偶数长度的回文串 for i in range(0, len_s-1): # 对每个i,寻找以它为中心的最长回文串 len1 = 1 if s[i] == s[i + 1]: len1 = len1 + 1 i = i - 1 j = i + 3 while i >= 0 and j < len_s: if s[i] == s[j]: len1 = len1 + 2 i = i - 1 j = j + 1 else: break if len1 > max_str_len: max_str_len = len1 max_str = s[i + 1:j] elif i>1 and s[i] == s[i - 1]: len1 = len1 + 1 i = i - 2 j = i + 3 while i >= 0 and j < len_s: if s[i] == s[j]: len1 = len1 + 2 i = i - 1 j = j - 1 else: break if len1 > max_str_len: max_str_len = len1 max_str = s[i + 1:j] return max_str
三.最长回文子串--Manacher算法
1)由于回文串的奇偶性造成了不同的对称轴位置,要队两种情况分别处理;
2)很多子串被重复多次访问。
char: a b a b a i : 0 1 2 3 4
当i==1和i==2时,左边的子串aba被重复访问了。
针对上述问题的分别改进:aba ———> #a#b#a#abba ———> #a#b#b#a#
char: # a # b # a # RL : 1 2 1 4 1 2 1RL-1: 0 1 0 3 0 1 0 i : 0 1 2 3 4 5 6char: # a # b # b # a # RL : 1 2 1 2 5 2 1 2 1RL-1: 0 1 0 1 4 1 0 1 0 i : 0 1 2 3 4 5 6 7 8
我们再引入一个辅助变量MaxRight
,表示当前访问到的所有回文子串,所能触及的最右一个字符的位置。另外还要记录下MaxRight
对应的回文串的对称轴所在的位置,记为pos
,它们的位置关系如下。
我们从左往右地访问字符串来求RL,假设当前访问到的位置为i
,即要求RL[i],在对应上图,i
必然是在po
右边的(obviously)。但我们更关注的是,i
是在MaxRight
的左边还是右边。我们分情况来讨论。
1)当i
在MaxRight
的左边
情况1)可以用下图来刻画:
我们知道,图中两个红色块之间(包括红色块)的串是回文的;并且以i
为对称轴的回文串,是与红色块间的回文串有所重叠的。我们找到i
关于pos
的对称位置j
,这个j
对应的RL[j]
我们是已经算过的。根据回文串的对称性,以i
为对称轴的回文串和以j
为对称轴的回文串,有一部分是相同的。这里又有两种细分的情况。
以
j
为对称轴的回文串比较短,短到像下图这样。
这时我们知道RL[i]至少不会小于RL[j],并且已经知道了部分的以i
为中心的回文串,于是可以令RL[i]=RL[j]
。但是以i
为对称轴的回文串可能实际上更长,因此我们试着以i
为对称轴,继续往左右两边扩展,直到左右两边字符不同,或者到达边界。
以
j
为对称轴的回文串很长,这么长:
这时,我们只能确定,两条蓝线之间的部分(即不超过MaxRight的部分)是回文的,于是从这个长度开始,尝试以i
为中心向左右两边扩展,,直到左右两边字符不同,或者到达边界。
不论以上哪种情况,之后都要尝试更新MaxRight
和pos
,因为有可能得到更大的MaxRight。
具体操作如下:
step 1: 令RL[i]=min(RL[2*pos-i], MaxRight-i)step 2: 以i为中心扩展回文串,直到左右两边字符不同,或者到达边界。step 3: 更新MaxRight和pos
2)当i
在MaxRight
的右边
遇到这种情况,说明以i
为对称轴的回文串还没有任何一个部分被访问过,于是只能从i
的左右两边开始尝试扩展了,当左右两边字符不同,或者到达字符串边界时停止。然后更新MaxRight
和pos
。
本人实现代码如下:(注:代码还可优化,没必要分这么多情况,比如最左边界只用取最小值即可)
class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ # 预处理,插入特殊字符 s = '#' + '#'.join(s) + '#' # 长度 len_s = len(s) # 回文半径初始化 RL = [0] * len_s # 当前最靠右的回文子串的相关信息,left和right关于pos对称 left = 0 right = 0 pos = 0 # 初始化最大长度回文子串 max_str = s[1] max_str_len = 1 # 依次求RL[i] for i in range(len_s): # step1:求RL[i] # 第一种情况:i在right的右边,即其相应的回文子串并没有被访问过 if i >= right: # 定义start为继续扩展回文子串的地方(关于i,从start开始向左) RL[i]=1 start = i - 1 else: # i关于pos的对称位置j j = 2 * pos - i if pos != 0 else 0 # 第二种情况:j及其回文串均在left到right内 if (j - RL[j]) >= left: RL[i] = RL[j] start = i - RL[i] # 第三种情况:j在left到right内,但其回文子串已经超出该范围 else: RL[i] = right - i + 1 start = 2 * i - right - 1 while start >= 0 and (2 * i - start) < len_s and s[start] == s[2 * i - start]: RL[i] += 1 start=start-1 # step2:更新最靠右回文子串的相关信息 if (i + RL[i] - 1) > right: right = i + RL[i] - 1 pos = i left = 2 * pos - right # 更新最长回文子串信息 if (RL[i] - 1) > max_str_len: max_str_len = RL[i] - 1 max_str = s[i - RL[i] + 1:i + RL[i]] return max_str.replace('#', '')算法复杂度分析:
时间复杂度:尽管代码里面有两层循环,通过amortized analysis我们可以得出,Manacher的时间复杂度是线性的。由于内层的循环只对尚未匹配的部分进行,因此对于每一个字符而言,只会进行一次,因此时间复杂度是O(n)。
- ★leetcode05_Longest Palindromic Substring
- LeetCode: Longest Palindromic Substring
- LeetCode Longest Palindromic Substring
- LeetCode: Longest Palindromic Substring
- [Leetcode] Longest Palindromic Substring
- Longest Palindromic substring
- [LeetCode] Longest Palindromic Substring
- LeetCode5:Longest Palindromic Substring
- Leetcode : Longest Palindromic Substring
- Longest Palindromic Substring
- Longest Palindromic Substring
- [LeetCode]Longest Palindromic Substring
- leetcode Longest Palindromic Substring
- Longest Palindromic Substring
- LeetCode-Longest Palindromic Substring
- Longest Palindromic Substring
- Longest Palindromic Substring
- [LeetCode] Longest Palindromic Substring
- ios 百度地图居中显示
- 学习摘抄Thread
- MYSQL 存储过程的一点学习
- 数据结构之堆的复习
- iOS获取UUID,并使用keychain存储,可用于封设备
- ★leetcode05_Longest Palindromic Substring
- LIB和DLL的区别和使用
- CSS居中和多列布局
- 文章标题
- 909422229__利用dom4j修改XML数据_进行增删改查【最新】
- 【UVa】10298 - Power Strings
- 2017滴滴出行面试题 n 张桌子吃饭的最大利润
- Lightoj1009——Back to Underworld(DFS)
- [Android开发]ScrollView中嵌套ListView