由于动态规划一直是一个比较难的点,因此在这里将leetcode刷题过程中碰到的比较常见的动态规划题记录下来。不定期更新。
1.最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
输入: "babad"
输出: "bab"
注意: "aba"也是一个有效答案。
先上代码:
class Solution(object):
def longestPalindrome(self, s):
tempstr=res=[]
for i in range(len(s)):
#odd
tempstr=self.longestPalindromeHelp(s,i,i)
if len(tempstr)>len(res):
res=tempstr
#even
tempstr=self.longestPalindromeHelp(s,i,i+1)
if len(tempstr)>len(res):
res=tempstr
return res
def longestPalindromeHelp(self,s,l,r):
while l>=0 and r<len(s) and s[l]==s[r]:
l-=1
r+=1
return s[l+1:r]
思路:从字符串的中间开始比较,若两字符相等,则同时向外移动一位,继续比较。需要注意的是,从中间开始需要分字符串为奇数和字符串为偶数两种情况。
2.最长公共字串和最长公共子序列
字串和子序列的区别在于字串要求字符必须是连续的,而子序列不要求连续。
最长公共字串的代码如下:
def find_substr(str1,str2):
dp=[[0 for j in range(len(str2)+1)] for i in range(len(str1)+1)]
maxlen=0
for i in range(len(str1)):
for j in range(len(str2)):
if str1[i]==str2[j]:
dp[i+1][j+1]=dp[i][j]+1
if dp[i+1][j+1]>maxlen:
maxlen=dp[i+1][j+1]
index=i
return maxlen,str1[index+1-maxlen:index+1]
最长公共子序列的递归公式如下:
代码如下:
def find_subseq(str1,str2):
dp=[[0 for j in range(len(str2)+1)] for i in range(len(str1)+1)]
ans=''
for i in range(len(str1)):
for j in range(len(str2)):
if str1[i]==str2[j]:
dp[i+1][j+1]=dp[i][j]+1
ans+=str1[i]
else:
dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1])
return dp[-1][-1],ans
需要指出的是该代码只能用于两字符串仅有一个最长公共子序列的情况。如果碰到如‘ABCBDAB’,‘BDCABA’会失效。
3.最长递增子序列(LIS)
复杂度为的方法:
class Solution(object):
def lengthOfLIS(self, nums):
if not nums:
return 0
dp=[1]*len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[i]>nums[j]:
dp[i]=max(dp[i],dp[j]+1)
return max(dp)