描述:
给定一个字符串 s
,找到 s
中最长的回文子串。你可以假设 s
的最大长度为 1000。
思路:中心扩散方法
当left = right 的时候,回文中心是一共字符,奇数回文子串
当right = left +1 的时候,此时回文中心是两个字符,偶数回文子串
思路:Mark 动态规划 -> 遍历左右边界
T1:如果一个子串两头的字符不相等,那该字符串一定不是回文串
T2:状态转移方程
上面的状态转移方程表示,当s[i]=s[j]时,如果s[i+1...j-1]是回文串,则s[i...j]也是回文串;如果s[i+1...j-1]不是回文串,则str[i...j]不是回文串。
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
dp = [[False] * n for _ in range(n)]
ans = ""
# 枚举子串的长度 l+1
for l in range(n):
# 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
for i in range(n):
j = i + l
if j >= len(s):
break
if l == 0:
dp[i][j] = True
elif l == 1:
dp[i][j] = (s[i] == s[j])
else:
dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
if dp[i][j] and l + 1 > len(ans):
ans = s[i:j+1]
return ans
leetcode67、回文子串的个数
思路是一样的 见下面
class Solution(object):
def longestPalindrome(self, s: str) -> str:
n = len(s)
dp = [[False] * n for _ in range(n)]
ans = 0
# 枚举子串的长度 l+1
for l in range(n):
# 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
for i in range(n):
j = i + l
if j >= n:
break
if l == 0:
dp[i][j] = True
elif l == 1:
dp[i][j] = (s[i] == s[j])
else:
dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
if dp[i][j] :
ans += 1
return ans
if __name__ == "__main__":
q=Solution()
test = "abc"
print(q.longestPalindrome(test))
leetcode131 分割回文串
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
输入: "aab"
输出: [ ["aa","b"], ["a","a","b"] ]
class Solution(object):
def partition(self, s: str) -> str:
n = len(s)
dp = [[] for _ in range(n + 1)]
for i in range(1, n +1):
for j in range(i):
if self.isPalindrome(s[j:i]):
if len(dp[j]) > 0:
for l in dp[j]:
dp[i].append(l+[s[j:i]])
else:
dp[i].append([s[j:i]])
return dp[-1]
def isPalindrome(self,s):
for i in range(len(s)>>1):
if s[i] != s[len(s)-1-i]:
return False
return True
if __name__ == "__main__":
q=Solution()
test = "aab"
print(q.partition(test))
思路:Manacher算法
**专门用于查找最长回文子串的算法,时间复杂度O(n)
**面试和笔试是不需要的
T1:将原始字符串做了预处理,在预处理字符串上执行 [动态规划] 和 [中心扩散] 方法
动态规划
Q1:什么是动态规划
动态规划就是寻找最优解的过程
Q2:判断是否用动态规划
一个问题看上去有很多种可能,但是求解最优解。如最大值,最小值,最短子串,最长子串等,选择动态规划
状态转移方程:从上一个状态到下一个状态存在一些变化,以及基于这些变化的最终决策结果
数学规划推导