LeetCode5. 最长回文子串(python)

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

解题思路:

manacher(马拉车算法)

马拉车是专门处理回文字符子串的一种算法。

首先,回文字符串有两种:长度为奇数,"aba";长度为偶数,"abba"。偶数长度的回文字符串不是以字符为对称中心,而马拉车算法通过对字符串的每个字符之间(包括首尾两端)插入一个特殊符号,如#(这个符号必须是原字符串中所没有的),来统一了奇偶的情况(#a#b#a#, #a#b#b#a#,长度均为奇数)。

其次,很好的利用了回文字符串的性质,核心公式:p[i] = min(max_right-i, p[2*center-i])

解读这个公式之前我们先初始化几个变量:

p :初始化全为0的列表,用来记录以当前位置为中心的最长的回文子串的半径
center :最长回文子串中心点
max_right :最长回文子串最远位置
max_s = 0 :最长回文子串中心点所在地的位置 

现在,假设我们已经求得了p[0, 1 , 2.....i-1],那么对于第i个位置来说:

首先要判断 i 的位置在max_right的右侧还是左侧:

当i < max_right,就再找到j(j 是 i 关于当前最长回文子串的中心点center的对称点),这里就利用了回文字符串的性质,

如果p[j] <= max_right-i,也就是说i加上j这一点的回文半径的长度还没有超过max_right,那么i这一点的回文半径大于等于p[j],再继续暴力向外搜索,找到该点的最长回文子串长度;

如果p[j] > max_right-i,那么对于max_right内的点就一定是对称的,则从max_right点再向外暴力搜索;

当i >= max_right,就无法利用回文字符串的特点,直接暴力搜索。

最后再更新一下最长字符子串和中心点。

综上,马拉车算法利用回文子串的性质将时间复杂度从O(N^2)降到了O(N),很抽象比较难理解,看代码应该会好很多

代码:

class Solution:
    def longestPalindrome(self, s: str) -> str:
        s = "!#" + "#".join(s) + "#?"
        center = 0 #最长回文子串中心点
        max_right = 0 #最长回文子串最远位置
        max_s = 0 #最长回文子串中心点所在地的位置

        p = [0] * (len(s)-1)
        for i in range(1, len(s)-1):
            if i < max_right:
                p[i] = min(max_right-i, p[2*center-i])
            else:
                p[i] = 1

            while i-p[i]>0 and i+p[i] max_right:
                max_right = i+p[i]
                center = i
            max_s = max(max_s, p[i])
        
        s=s[p.index(max_s)-(max_s-1): p.index(max_s)+(max_s-1)]
        s=s.replace('#','') 
        
        return s

最后再附一下暴力解法,很暴力很暴力。。。。。

class Solution:
    def countSubstrings(self, s: str) -> int:
        num = []
        for k in range(2, len(s)+1): #k:滑动窗口的长度
            for i in range(len(s)-(k-1)):
                st = s[i:i+k]
                n = 0
               
                if len(st)%2 == 0:
                    for j in range(int(len(st)/2)):
                        if st[j] == st[len(st)-1-j]:
                            n+=1
                    if n == int(len(st)/2):
                        num.append(st)
                
                else:
                    for j in range(math.floor(len(st)/2)):
                        if st[j] == st[len(st)-1-j]:
                            n+=1
                    if n == math.floor(len(st)/2):
                        num.append(st)
        
        return len(num) + len(s)

 

你可能感兴趣的:(LeetCode)