动态规划做题总结

动态规划的本质是填表,自底向上的完成DP数组的构建。难点在于DP数组的定义以及状态转移方程的构建。

一维DP

最长公共子串

class Solution:
    def LCS(self , str1: str, str2: str) -> str:
        #让str1为较长的字符串
        if len(str1) < len(str2): 
            str1, str2 = str2, str1
        res = ''
        max_len = 0
        #遍历str1的长度
        for i in range(len(str1)): 
            #查找是否存在
            if str1[i - max_len : i + 1] in str2: 
                res = str1[i - max_len : i + 1]
                max_len += 1
        return res

换零钱

class Solution:
    def minMoney(self , arr: List[int], aim: int) -> int:
        # write code here
        if len(arr)==0:
            return -1
        if aim==0:
            return 0
        pd=[aim+1]*(aim+1)
        pd[0]=0
        for i in range(len(pd)):
            for j in arr:
                if i-j<0:
                    continue
                pd[i]=min(pd[i],pd[i-j]+1)
        if pd[aim]==aim+1:
            return -1
        else:
            return pd[aim]

最长上升子序列

class Solution:
    def LIS(self , arr: List[int]) -> int:
        # write code here
        dp=[0]*len(arr)
        max1=0
        for i in range(len(dp)):
            max2=0
            for j in range(i):
                if arr[j]<=arr[i]:
                    max2=max(max2,dp[j])
            dp[i]=max2+1
            max1=max(max1,dp[i])
        return max1

打家劫舍系列

class Solution:
    def rob(self , nums: List[int]) -> int:
        # write code here
        res1=0
        res2=0
        dp=[0]*(len(nums)-1)
        # 不偷最后一家,
        dp[0]=nums[0]
        dp[1]=max(nums[0],nums[1])
        for i in range(2,len(dp)):
            dp[i]=max(dp[i-1],dp[i-2]+nums[i])
        res1=dp[-1]
        # 偷最后一家,即不偷第一家和倒数第二家
        dp[0]=nums[1]
        dp[1]=max(nums[1],nums[2])
        for i in range(2,len(dp)):
            dp[i]=max(dp[i-1],dp[i-2]+nums[i+1])
        res2=dp[-3]+nums[-1]
        return max(res1,res2)

二维DP

矩阵最小路径和

class Solution:
    def minPathSum(self , matrix: List[List[int]]) -> int:
        # write code here
        m=len(matrix)
        n=len(matrix[0])
        dp=[[0]*n for i in range(m)]
        dp[0][0]=matrix[0][0]
        for i in range(1,n):
            dp[0][i]=dp[0][i-1]+matrix[0][i]
        for i in range(1,m):
            dp[i][0]=dp[i-1][0]+matrix[i][0]
        for i in range(1,m):
            for j in range(1,n):
                dp[i][j]=min(dp[i][j-1],dp[i-1][j])+matrix[i][j]
        return dp[-1][-1]

编辑距离

class Solution:
    def editDistance(self , str1: str, str2: str) -> int:
        # write code here
        m=len(str1)+1
        n=len(str2)+1
        # dp[i][j]str1[0...i],str2[0....j]的最小编辑距离
        dp=[[0]*n for i in range(m)]
        for i in range(1,n):
            dp[0][i]=i
        for i in range(1,m):
            dp[i][0]=i
        for i in range(1,m):
            for j in range(1,n):
                if str1[i-1]==str2[j-1]:
                    dp[i][j]=dp[i-1][j-1]
                else:
                    dp[i][j]=min(
                        dp[i-1][j]+1,
                        dp[i][j-1]+1,
                        dp[i-1][j-1]+1
                    )
        return dp[-1][-1]

三维DP

股票买卖

dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
#max( 今天选择 rest,         今天选择 buy         )
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
#max( 今天选择 rest,        今天选择 sell       )

这里着重提醒一下,时刻牢记「状态」的定义,状态 k 的定义并不是「已进行的交易次数」,而是「最大交易次数的上限限制」。如果确定今天进行一次交易,且要保证截至今天最大交易次数上限为 k,那么昨天的最大交易次数上限必须是 k - 1。

class Solution:
    def maxProfit(self , prices: List[int]) -> int:
        # write code here
        max_k=2
        dp=[[[0]*(2) for i in range(3)] for i in range(len(prices))]
        dp[0][2][1]=-prices[0]
        dp[0][1][1]=-prices[0]
        for i in range(1,len(prices)):
            for k in range(1,max_k+1):
                dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+prices[i])
                dp[i][k][1]=max(dp[i-1][k-1][0]-prices[i],dp[i-1][k][1])
        return dp[-1][max_k][0]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值