回文串
验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 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
回文子串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 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
最长回文子串
给定一个字符串 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]
最长回文子序列
给定一个字符串 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)