Harukaze

 

【力扣】DP合集

动态规划:

322零钱兑换 https://leetcode-cn.com/problems/coin-change/ 失败

198 打家劫舍 https://leetcode-cn.com/problems/house-robber/submissions/ 成功

  

213 打家劫舍II https://leetcode-cn.com/problems/house-robber-ii/ 失败  

减而治之和分而治之,这题把环形分为单排就是分而治之,即把一个问题分成多个规模更小的子问题。

377 打家劫舍III https://leetcode-cn.com/problems/house-robber-iii/ 树形dp 失败

视角集中在最后一个加入的孩子节点了,应该调整到根节点(第一个节点)分治成根节点的子树问题

279 完全平方数 https://leetcode-cn.com/problems/perfect-squares/  失败,情况划分为子问题时复杂了,分了两种情况,而且函数嵌套self的声明问题完全是懵的

343 整数拆分 https://leetcode-cn.com/problems/integer-break/ 失败,将简单问题复杂化了,状态转移方程与dp[]的定义根本没想好。

416 分割等和子集 https://leetcode-cn.com/problems/partition-equal-subset-sum/ 失败

一个一个物品去尝试,一点一点考虑能够容纳的容积的大小,整个过程就像是在填写一张二维表格

定义的dp[][]不仅仅是二维的,而且是具有前缀性质的

474 一和零 https://leetcode-cn.com/problems/ones-and-zeroes/ 失败 局限于二维数组,应该是三维数组

494 目标和 https://leetcode-cn.com/problems/target-sum/solution/494-mu-biao-he-dong-tai-gui-hua-zhi-01be-78ll/ 思路转变,转为0~1背包问题 ,如何巧妙转化,之后就是套公式了

518 完全背包问题 https://leetcode-cn.com/problems/coin-change-2/submissions/ 成功

 123 买卖股票最佳时机 https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ 成功(贪心)

第三种方法:DP动态规划,第i天只有两种状态,不持有或持有股票,当天不持有股票的状态可能来自昨天卖出或者昨天也不持有,同理,当天持有股票的状态可能来自昨天买入或者昨天也持有中,取最后一天的不持有股票状态就是问题的解

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
        n = len(prices)
        dp = [[0]*2 for _ in range(n)]
        # dp[i][0]表示第i天不持有股票, dp[i][1]表示第i天持有股票
        dp[0][0], dp[0][1] = 0, - prices[0]
        for i in range(1, n):
            dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
        return dp[n-1][0]

123 买卖股票最佳时机III https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-iii-by-wrnt/ 失败 第三维交易次数没想明白

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        # dp[i][j][k] 表示
        # 第i天 持有和不持有 交易k次
        dp = [[[0]*3 for _ in range(2)] for _ in range(n)]
        
        # 初始化 第0天的时候 持有和不持有其实与交易次数无关 和之前的初始化是一样的
        for i in range(3):
            dp[0][0][i],dp[0][1][i] = 0,-prices[0]

        # 按照天数和交易次数来遍历
        for i in range(1,n):
            for k in range(3):
                # 和以往的题目一样 卖出的时候算作一次交易 这里用到了k-1 所以k为0要分开讨论
                # 想一想k为0时候的意思 第i天不持有而且没有卖出过 只能是i-1天的时候也不持有
                dp[i][0][k] = max(dp[i-1][0][k],dp[i-1][1][k-1]+prices[i]) if k!=0 else dp[i-1][0][k]
                dp[i][1][k] = max(dp[i-1][1][k],dp[i-1][0][k]  -prices[i])
        # 和以往的题目一样 最大值出现在最后一天不持有的情况下
        return max(dp[n-1][0])

188 买卖股票的最佳时机 VI https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/ 跟上题一样

309 最佳买卖股票时期含冷冻期  https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ 失败

714 买卖股票的最佳时机含手续费  https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/

300 最长递增子序列 https://leetcode-cn.com/problems/longest-increasing-subsequence/ 看过答案,略微修改 ,定义的dp[i][]为2维,且表示前i个元素,第二维虽然设置为0不选|1选,实际填表[1]的情况并未按照选择了该位置元素的情况填是出错的主要原因。答案给出定义dp[i]为1维,i为以i为结尾的字符串(暗含必选此元素的意味)

1143 最长公共子序列 https://leetcode-cn.com/problems/longest-common-subsequence/ 失败,自己定义的dp[][]一维二维定义不一样,多出了很多特判情形,错了

72 编辑距离 https://leetcode-cn.com/problems/edit-distance/ 失败 看过答案知道了。

  • 问题1:如果 word1[0..i-1] 到 word2[0..j-1] 的变换需要消耗 k 步,那 word1[0..i] 到 word2[0..j] 的变换需要几步呢?

  • 答:先使用 k 步,把 word1[0..i-1] 变换到 word2[0..j-1],消耗 k 步。再把 word1[i] 改成 word2[j],就行了。如果 word1[i] == word2[j],什么也不用做,一共消耗 k 步,否则需要修改,一共消耗 k + 1 步。

  • 问题2:如果 word1[0..i-1] 到 word2[0..j] 的变换需要消耗 k 步,那 word1[0..i] 到 word2[0..j] 的变换需要消耗几步呢?

  • 答:先经过 k 步,把 word1[0..i-1] 变换到 word2[0..j],消耗掉 k 步,再把 word1[i] 删除,这样,word1[0..i] 就完全变成了 word2[0..j] 了。一共 k + 1 步。

  • 问题3:如果 word1[0..i] 到 word2[0..j-1] 的变换需要消耗 k 步,那 word1[0..i] 到 word2[0..j] 的变换需要消耗几步呢?

  • 答:先经过 k 步,把 word1[0..i] 变换成 word2[0..j-1],消耗掉 k 步,接下来,再插入一个字符 word2[j], word1[0..i] 就完全变成了 word2[0..j] 了。

从上面三个问题来看,word1[0..i] 变换成 word2[0..j] 主要有三种手段,用哪个消耗少,就用哪个

10 正则表达式匹配,https://leetcode-cn.com/problems/regular-expression-matching/ 失败,状态转移公式*不常规。 

120 三角形最小路径之和 https://leetcode-cn.com/problems/triangle/ 看过答案修改成功,初始边界定义错误,导致递归错误,递归代码逻辑没问题,第dp[i][i]需要特判未考虑

53 最大子序和  看答案修改正确,https://leetcode-cn.com/problems/maximum-subarray/ 负数就不选,不选就是0

152 乘积最大子数组 https://leetcode-cn.com/problems/maximum-product-subarray/ 失败,未维护最小值dp数组,反而想负数情况费分类讨论,错误

5 最长回文子串 https://leetcode-cn.com/problems/longest-palindromic-substring/submissions/ 失败,答案很漂亮

class Solution:
    def longestPalindrome(self, s: str) -> str:
        
        size = len(s)
        # 特殊处理
        if size == 1:
            return s
        # 创建动态规划dynamic programing表
        dp = [[False for _ in range(size)] for _ in range(size)]
        # 初始长度为1,这样万一不存在回文,就返回第一个值(初始条件设置的时候一定要考虑输出)
        max_len = 1
        start = 0
        for j in range(1,size):
            for i in range(j):
                # 边界条件:
                # 只要头尾相等(s[i]==s[j])就能返回True
                if j-i<=2:
                    if s[i]==s[j]:
                        dp[i][j] = True
                        cur_len = j-i+1
                # 状态转移方程 
                # 当前dp[i][j]状态:头尾相等(s[i]==s[j])
                # 过去dp[i][j]状态:去掉头尾之后还是一个回文(dp[i+1][j-1] is True)
                else:
                    if s[i]==s[j] and dp[i+1][j-1]:
                        dp[i][j] = True
                        cur_len = j-i+1
                # 出现回文更新输出
                if dp[i][j]:
                    if cur_len > max_len:
                        max_len = cur_len
                        start = i

        return s[start:start+max_len]

1371

 

posted on 2021-08-12 16:42  Harukaze  阅读(180)  评论(0)    收藏  举报

导航