回文串

验证回文串

125. 验证回文串

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:

输入: "A man, a plan, a canal: Panama"
输出: true

示例 2:

输入: "race a car"
输出: false

分析

双指针

import re
class Solution:
    def isPalindrome(self, s: str) -> bool:
        if not s:
            return True
        # s = ''.join(filter(str.isalnum,s)).lower()
        s = re.sub('[^a-zA-Z0-9]','',s).lower()

        left, right = 0, len(s)-1
        while left < right:
            if s[left] != s[right]:
                return False
            left += 1
            right -= 1
        return True

回文子串

647. 回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例 1:

输入:"abc"
输出:3
解释:三个回文子串: "a", "b", "c"

示例 2:

输入:"aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"

分析

  • 暴力法

    遍历每个字串,判断是否为回文串

    时间复杂度 \(O(n^3)\)

  • 中心扩展

    以每个中心向两边扩展,前一个字串是回文,如果两边字符相等就是回文 \(O(n^2)\)

    class Solution:
        def countSubstrings(self, s: str) -> int:
            if not s:
                return 0
            count = 0
            for i in range(len(s)):
                left, right = i, i #奇数中心
                while left >= 0 and right < len(s) and s[left] == s[right]:
                    count += 1
                    left -= 1
                    right += 1
                left, right = i, i+1 #偶数中心
                while left >= 0 and right < len(s) and s[left] == s[right]:
                    count += 1
                    left -= 1
                    right += 1
            return count
    

最长回文子串

5. 最长回文子串

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

示例 1:

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

分析

  • 暴力解法:

    找到所有子串,判断是否为回文串并记录长度

    时间复杂度为:\(O(n^3)\)

    空间复杂度为:\(O(n)\)

  • 动态规划:

    状态表示当前子串是否为回文串;

    状态转移:子串为回文串,左右两边相等则为回文

    def longestPalindrome(self, s: str) -> str:
            size = len(s)
            if size < 2:
                return s
    
            dp = [[False for _ in range(size)] for _ in range(size)]
    
            max_len = 1
            start = 0
    
            for i in range(size):
                dp[i][i] = True
    
            for j in range(1, size):
                for i in range(0, j):
                    if s[i] == s[j]:
                        if j - i < 3:
                            dp[i][j] = True
                        else:
                            dp[i][j] = dp[i + 1][j - 1]
                    else:
                        dp[i][j] = False
    
                    if dp[i][j]:
                        cur_len = j - i + 1
                        if cur_len > max_len:
                            max_len = cur_len
                            start = i
            return s[start:start + max_len]
    
  • 中心扩展

    class Solution:
        def longestPalindrome(self, s: str) -> str:
            if not s:
                return ""
            start, end = 0, 0
            for i in range(len(s)):
                left, right = i, i #奇数中心
                while left >= 0 and right < len(s) and s[left] == s[right]:
                    if right-left > end - start:
                        start, end = left, right
                    left -= 1
                    right += 1
    
                left, right = i, i+1 #偶数中心
                while left >= 0 and right < len(s) and s[left] == s[right]:
                    if right-left > end - start:
                        start, end = left, right
                    left -= 1
                    right += 1
            return s[start:end+1]
    

最长回文子序列

516. 最长回文子序列

给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000

示例 1:
输入:

"bbbab"

输出:

4

分析

  • 动态规划

    class Solution:
        def longestPalindromeSubseq(self, s: str) -> int:
            n  = len(s)
            dp = [[0]*n for _ in range(n)]
    
            for i in range(n):
                dp[i][i] = 1
    
            for j in range(1,n):
                for i in range(j-1,-1,-1):
                    if s[i] == s[j]:
                        dp[i][j] = dp[i+1][j-1] + 2
                    else:
                        dp[i][j] = max(dp[i+1][j],dp[i][j-1])
            return dp[0][-1]
    

最短回文串

我们需要在给定的字符串 s 前面添加字符串 s',得到最短的回文串。这里我们用 s'+s表示得到的回文串。显然,这等价于找到最短的字符串 s',使得 s'+s是一个回文串。

  • 将原序列逆序,依次取前i个元素作为前缀,构成回文

    class Solution:
        def shortestPalindrome(self, s: str) -> str:
            # 先逆序 取前i个拼接 构成回文串
            if not s:
                return ""
            reverse = s[::-1]
            for i in range(len(s)):
                subs = reverse[:i]+s
                if subs == subs[::-1]:
                    return subs
            return None
    
  • 找到原序列的回文前缀(KMP)

posted @ 2020-08-30 10:44  鱼与鱼  阅读(591)  评论(0编辑  收藏  举报