Leetcode(4)寻找两个有序数组的中位数
[题目表述]:
给定一个字符串 s,找到 s 中 最长 的回文子串。你可以假设 s 的最大长度为 1000。‘
第一种方法:未完成;利用回文子串的特点
一开始我的思路如下:回文子串的特点是首尾字母相同,所以我对每一个字母都找到位于它后面的相同字母,利用切片判断这一段是否为回文子串(str[i:j]==str[i:j][::-1]).时间复杂度很高,主要是因为str.find操作非常耗时.
class Solution(object): def longestPalindrome(self, s): """ :type s: str :rtype: str """ res="" res+=s[0] res_star=0 res_end=0 Maxsize=1 for i in range(len(s)): nPos=i i_number=s[i:].count(s[i]) if i_number==1: continue while i_number!=1: if s[i+1]==s[i]: i_number=i_number-1 nPos=i+1 if Maxsize!=max(Maxsize,len(s[i:nPos+1])): Maxsize=len(s[i:nPos+1]) res_star,res_end=i,nPos+1 res+=s[i:nPos+1] else: nPos=s[nPos+1:].index(s[i]) i_number=i_number-1 if s[i:nPos+1]==s[i:nPos+1:-1]: if Maxsize!=max(Maxsize,len(s[i:nPos+1])): res_star,res_end=i,nPos+1 res+=s[i:nPos+1] return res[res_star:res_end+1]
学习
str.find /str.index
切片 回文子串
第二种方法:动态规划
执行用时:3828 ms; 内存消耗:11.7MB 效果:有点差 O(n2)
class Solution: def longestPalindrome(self, s): """ :type s: str :rtype: str """ max = 0 palindromic = '' if len(s) == 0 else s[0] for i in range(len(s)): length = 1 while i - length >=0 and i + length < len(s) and s[i-length] == s[i+length]: tmp = s[i-length:i+length+1] ##奇回文 if len(tmp) > max: max = len(tmp) palindromic = tmp length += 1 length = 1 while i - length + 1 >=0 and i + length < len(s) and s[i-length+1] == s[i+length]: tmp = s[i-length+1:i+length+1] ##偶回文 if len(tmp) > max: max = len(tmp) palindromic = tmp length += 1 return palindromic
学习
动态规划的思想是首先判断相邻的字符串是否是回文,然后继续判断连续的三个字符是否是回文,然后是四个,…,直到判断完整个字符串 ——对子串的判断;状态转换
动态规划思想
奇偶回文
第三种方法:Manacher马拉车法:添加辅助标志
执行用时:80 ms; 内存消耗:12MB 效果:非常好 O(n)
class Solution: #Manacher algorithm #http://en.wikipedia.org/wiki/Longest_palindromic_substring def longestPalindrome(self, s): # Transform S into T. # For example, S = "abba", T = "^#a#b#b#a#$". # ^ and $ signs are sentinels appended to each end to avoid bounds checking T = '#'.join('^{}$'.format(s)) n = len(T) P = [0] * n C = R = 0 for i in range (1, n-1): ##首尾是终止符 P[i] = (R > i) and min(R - i, P[2*C - i]) # equals to i' = C - (i-C) #如果R>i且R-i大,则P[i]=P[j] # Attempt to expand palindrome centered at i 两者相等,因为R范围内对称 while T[i + 1 + P[i]] == T[i - 1 - P[i]]: P[i] += 1 # If palindrome centered at i expand past R, # adjust center based on expanded palindrome. if i + P[i] > R: #最终求出P[i]后设立新C,R C=center R=range 利用2*C-i拉着i走一样 C, R = i, i + P[i] # Find the maximum element in P. maxLen, centerIndex = max((n, i) for i, n in enumerate(P)) return s[(centerIndex - maxLen)//2: (centerIndex + maxLen)//2] #因为len(P)=len(s)两倍多
学习:
两头需要边界符
字符.join
马拉车算法思想
list.enumerate()
第四种方法:新增字母判断是否仍是回文
执行用时:72 ms; 内存消耗:11.8MB 效果:非常好 O(n) 由于使用切片,所以比马拉车快
class Solution: # @return a string def longestPalindrome(self, s): if len(s)==0: return s maxLen=1 start=0 for i in xrange(len(s)): if i-maxLen >=1 and s[i-maxLen-1:i+1]==s[i-maxLen-1:i+1][::-1]: start=i-maxLen-1 maxLen+=2 continue if i-maxLen >=0 and s[i-maxLen:i+1]==s[i-maxLen:i+1][::-1]: start=i-maxLen maxLen+=1 return s[start:start+maxLen]
学习
思路是:遍历,第i个字母加上后面一个字母,看i-Max-1到i+1(就是从第i个往后面看)是不是回文,如果是,则回文串起点跟Max被记录下来;如果这样不是,那就看i-Max到i+1是不是回文,如果是也是一样的操作。
因为前面字符串加上新的字符是回文的话,就只有两种可能性,
①:bb+b这种 ②:a bb+a这种,①记录下Max=2,
②则在a前面Max+1找,即是i-Max-1,然后记录下Max=3,
做切片的时候就是start:start+Max,Max自动会-1的,保证半径符合。