动态规划的套路


前言

本文内容来自wisdompeak大神的<残酷刷题群算法小讲座:动态规划的套路>。大神已经总结的很好了。所以下面的内容,就是给出大神举的例子(Leetcode上的题)。自己尝试写出python版本的代码。

一、动态规划的思考艺术

LeetCode 62

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        dp = [[1 for _ in range(n)] for _ in range(m)]
        for i in range(1,m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[-1][-1]

动态规划算法对每个子问题只求解一次,讲其结果保存在一张中,从而避免每次遇到各个子问题时重新计算答案。可以将代码中的dp打印到表格里看看。

import xlwt

def writedp(dp):
    excel = xlwt.Workbook(encoding='utf-8')
    sheet = excel.add_sheet("dp")
    for i in range(len(dp)):
        for j in range(len(dp[0])):
            sheet.write(i, j, dp[i][j])
    excel.save("dp.xls")

class Solution(object):
    def uniquePaths(self, m, n):
        """
        :type m: int
        :type n: int
        :rtype: int
        """
        dp = [[1 for _ in range(n)] for _ in range(m)]
        for i in range(1,m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        writedp(dp)
        return dp[-1][-1]

s = Solution()
s.uniquePaths(3, 7)

把dp里的内容打印到Excel表格里。

在这里插入图片描述

二、第一类基本型(“时间序列”型)

b站的url里好像没有定位视频播放位置的参数,因为我想给一个链接,可以定位到具体的播放位置。(如果有的话,希望在评论区说一下)这里记录一下,播放该内容开始的时间。
8:16(该内容播放的开始时间)

1 打家劫舍

LC 198

class Solution(object):
    def rob(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        dp = [[0 for _ in range(2)] for i in range(len(nums))]
        dp[0][0] = nums[0]        
        for i in range(1, len(nums)):
                dp[i][0] = dp[i - 1][1] + nums[i]
                dp[i][1] = max(dp[i-1][1], dp[i-1][0])
        return max(dp[-1])

2 打家劫舍II

LC 213

3 买卖股票的最佳时机 III

LC 123

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        dp = [[0 for _ in range(4)] for _ in range(len(prices))]
        dp[0][0] = -prices[0]
        dp[0][2] = -prices[0]
        for i in range(1, len(prices)):
            dp[i][0] = max(-prices[i], dp[i-1][0])
            dp[i][1] = max(dp[i-1][0] + prices[i], dp[i-1][1])
            dp[i][2] = max(dp[i-1][1] - prices[i], dp[i-1][2])
            dp[i][3] = max(dp[i-1][2] + prices[i], dp[i-1][3])
        return max(dp[-1])

4 最佳买卖股票时机含冷冻期

LC 309

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        # 定义三种状态:买入,卖出,冷冻期
        dp = [[0 for _ in range(3)] for _ in range(len(prices))]
        dp[0][0] = -prices[0]
        for i in range(1, len(prices)):
            dp[i][0] = max(dp[i-1][2] - prices[i], dp[i-1][0])
            dp[i][1] = max(dp[i-1][0] + prices[i], dp[i-1][1])
            dp[i][2] = dp[i-1][1]
        return max(dp[-1])

5 摆动序列

LC 376

class Solution(object):
    def wiggleMaxLength(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        #定义两种状态:正,负
        up, down = 1, 1
        for i in range(1, len(nums)):
            if nums[i] > nums[i-1]:
                up = down + 1
            elif nums[i] < nums[i-1]:
                down = up + 1
                
        return max(up, down)

6 删除一次得到子数组最大和

LC 1186

class Solution(object):
    def maximumSum(self, arr):
        """
        :type arr: List[int]
        :rtype: int
        """
        dp = [[0 for _ in range(2)] for _ in range(len(arr))]
        dp[0][0] = arr[0]
        ans = arr[0]
        for i in range(1, len(arr)):
            dp[i][0] = max(dp[i-1][0] + arr[i], arr[i])
            dp[i][1] = max(dp[i-1][0], dp[i-1][1] + arr[i])
            ans = max(dp[i][0], dp[i][1], ans)
        return ans

二、第二类基本型(“时间序列”加强版)

给出一个序列,其中每一个元素可以认为"一天":但"今天"的状态和之前的"某一天"有关,需要挑选。
43:00(播放开始时间)

1 最长递增子序列

LC300

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        dp = [1 for i in range(len(nums))]
        for i in range(1, len(nums)):
            for j in range(i):
                if nums[i] > nums[j]:
                    dp[i] = max(dp[i], dp[j] + 1)
        return max(dp)

2 最大整除子集

LC 368

3 填充书架

LC 1105

三、双序列型

1:01:50(该内容播放的开始时间)

1 最长公共子序列

LC 1143

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        dp = [[0 for _ in range(len(text2) + 1)] for _ in range(len(text1) + 1)]
        for i in range(1, len(text1) + 1):
            for j in range(1, len(text2) + 1):
                if text1[i - 1] == text2[j - 1]:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        return dp[-1][-1]

2 最短公共超序列

LC 1092

3 编辑距离

LC 72

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        #这道题有个小技巧。就是在word1,word2前加一个空字符
        dp = [[0 for _ in range(len(word2) + 1)] for _ in range(len(word1) + 1)]
        for i in range(len(word1) + 1):
            dp[i][0] = i
        for i in range(len(word2) + 1):
            dp[0][i] = i
        for i in range(1, len(word1) + 1):
            for j in range(1, len(word2) + 1):
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i-1][j-1]
                else:
                    dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1
        return dp[-1][-1]
         

4 交错字符串

LC 97

5 不同的子序列

LC 115

四、第一类区间型DP

1:31:00(播放开始时间)

1 分割回文串 III

LC 1278

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值