leetcode 516 Longest Palindromic Subsequence
leetcode 516 Longest Palindromic Subsequence
先看一下题目原文:
Given a string s, find the longest palindromic subsequence’s length in s. You may assume that the maximum length of s is 1000.
Example 1:
Input:
“bbbab”
Output:
4
One possible longest palindromic subsequence is “bbbb”.
Example 2:
Input:
“cbbd”
Output:
2
One possible longest palindromic subsequence is “bb”.
这里对于题目的认识,最长公共子串(Longest Common Substring)与最长公共子序列(Longest Common Subsequence)的区别: 子串要求在原字符串中是连续的,而子序列则只需保持相对顺序,并不要求连续。
这道题考察的是动态规划类型的算法,也就是DP(Dynamic Programming)问题,如果一个问题的每次决策依赖于当前的状态的时候,并且当前的状态又会引起下一次的状态转移,则可以用动态规划问题来解决这个问题。
对于这个题来讲,最长的子串我们默认为与母串等长也就是长度为n,那么他的始终端点假设[i,j],此时根据s[i]和s[j]的状态,分成两种情况,第一是相等,则等于n-2长度的字符串的最长子串 +2, 不相等的情况下,等于n-1长度的字符串的最长子串,那这里n-1的字符串有两种情况,所以用一个max()来得出结果。此处参考花花酱的示意图:
示意图的左边是一个伪代码段,这里在我的代码注释中解释了,每次遍历的数值原因,这里双循环所以时间复杂度是O(n^2),两维列表,空间复杂度也是一样的。
def longestPalindromeSubseq(self, s: str) -> int:
l = len(s)
if l == 0: return 0
if l == 1: return 1
#定义储存答案的字典
#初始化填充
#因为answer的下标是从i到j所以创建一个i*j最大取值范围的矩阵
#且对角线上的值是1 因为i==j的时候是奇数 可以作为一个长度
ans = [[0]*l for _ in range(l)]
for n in range(l):
ans[n][n] = 1
#i最大是l-1 j最大也是l-1
#length指的是子序列的长度,是从1到全长,如果用range记得最后一个+1
for length in range(2,l+1):
#i是这个sub string 的左下标 j 是右下标
#i的取值范围就是在1到 (序列全长 - 子序列总长),在range里就是(0,l-length+1)
#例如全长5 总长3 【12345】那么 最后一个序列就是 【345】 那么i的最后一个值就是下标2 -> 5-3
for i in range(l-length+1):
#j的取值范围就是在 i+总长-1
j = i+length-1
if s[i]==s[j]:
#如果左右相等 那么这个最长回文长度就等于去掉左右两端的子串的最长长度+2
ans[i][j] = ans[i+1][j-1]+2
else:
#如果左右不等,那么这个解就是分解成去头或者去尾的最大的那个
ans[i][j] = max(ans[i+1][j],ans[i][j-1])
return ans[0][l-1]
以后补充一个优化速度和空间复杂度的办法。
当然DP问题也会有递归遍历的解法,同样的问题,普遍递归要慢于迭代循环。后期可以补充一个递归的方法。