代码随想录算法训练营-动态规划DP

重点五步法:

1. dp数组以及下表含义是什么?

2. 如何初始化

3. 递推公式是什么

4. 遍历顺序

5. 打印dp数组

509. Fibonacci Number

class Solution:
    def fib(self, n: int) -> int:
        if n == 0:
            return 0
        dp = [0] * (n + 1)
        dp[1] = 1
        for i in range(2, n + 1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[-1]

70. Climbing Stairs

class Solution:
    def climbStairs(self, n: int) -> int:
        if n in (1, 2):
            return n
        dp_1, dp_2 = 1, 2
        for i in range(3, n + 1):
            new = dp_1 + dp_2
            dp_1, dp_2 = dp_2, new
        return new

746. Min Cost Climbing Stairs

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        if n <= 2:
            return min(cost)
        dp2 = 0
        dp1 = 0
        for i in range(2, n + 1):
            new = min(dp1 + cost[i - 1], dp2 + cost[i - 2])
            dp2, dp1 = dp1, new
        return new

62. Unique Paths

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        if n <= 2:
            return min(cost)
        dp2 = 0
        dp1 = 0
        for i in range(2, n + 1):
            new = min(dp1 + cost[i - 1], dp2 + cost[i - 2])
            dp2, dp1 = dp1, new
        return new

63. Unique Paths II

class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
        m, n = len(obstacleGrid), len(obstacleGrid[0])
        dp = [[1 for _ in range(m)] for _ in range(n)]
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i - 1][j] * (1- obstacleGrid[i - 1][j]) + dp[i][j - 1] * (1 - obstacleGrid[i][j - 1])
        return dp[m - 1][n - 1]

343. Integer Break

class Solution:
    def integerBreak(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[2] = 1
        for i in range(3, n + 1):
            for j in range(1, i // 2 + 1):
                dp[i] = max(dp[i],j * dp[i - j], j * (i-j))
        print(dp)
        return dp[-1]

96. Unique Binary Seacrch Trees

class Solution:
    def numTrees(self, n: int) -> int:
        if n in (1, 0):
            return 1
        dp = [0] * (n + 1)
        dp[0], dp[1], dp[2] =1, 1, 2
        for i in range(3, n + 1):
            for j in range(1, i + 1):
                dp[i] += dp[j - 1] * dp[i - j]
        print(dp)
        return dp[-1]

背包问题:

概述: 01背包 完全背包

01背包: n种物品, 每个物品只有一个, 每个物品有相应重量和价值, 给一个背包能装重量m, 最多能装多少价值

完全背包: n种物品, 每种物品无限个

多重背包: n种物品, 每种物品数量各不相同

dp数组如何定义?

1. 二维dp数组: dp[i][j]表示

    0到i之间的物品任取 放进容量为j的背包里

    递推公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]])

    不放物品i: dp[i - 1][j]

    放物品i: dp[i - 1][j - weight[i]] + value[i]

    初始化:

    j = 0时 dp[i][j] = 0 for all i

    i = 0时 dp[i][j] = (j >= weight[0]) * value[0]

2. 一维dp数组:

        直接覆盖当前层, 因为二维数组是取决于上一行, 滚动数组

        dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

       初始化: dp = [0, ..., 0], 这样从后向前更新 递推公式中原dp[j]不影响结果

        更新顺序必须后到前, 因为后面的更新依赖于前面的数值

检查一个list里是否存在一个和等于target 或者尽可能接近target的task可以作为背包问题考虑

416. Partition Equal Subset Sum

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total = sum(nums)
        if total % 2 == 1:
            return False
        # 想象成重量价值等价的01背包问题
        # 重量 = 价值, 最大化价值 = 最大化重量 = 装满
        target = int(total / 2)
        dp = [0] * int(target + 1)
        for i in range(len(nums)):
            for j in range(target, nums[i] - 1, -1):
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
        return dp[-1] == target

494. Target Sum

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        if sum(nums) < abs(target):
            return 0
        total = sum(nums) + target
        if total % 2 == 1:
            return 0
        goal = total // 2
        dp = [[0 for _ in range(goal + 1)] for _ in range(len(nums))]
        dp[0][0] = 1
        if nums[0] <= goal:
            dp[0][nums[0]] += 1

        for i in range(1, len(nums)):
            for j in range(goal + 1):
                if j >= nums[i]:
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i]]
                else:
                    dp[i][j] = dp[i - 1][j]
        print(dp)
        return dp[-1][-1]

        

        

474. Ones and Zeros

class Solution:
    def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
        dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
        for item in strs:
            x = item.count('0')
            y = item.count('1')
            for i in range(m, x - 1, -1):
                for j in range(n, y - 1, -1):
                    dp[i][j] = max(dp[i][j], dp[i-x][j - y] + 1)
        return dp[-1][-1]

完全背包理论基础

区别在于每个物品可以使用无数次

其实只需要正序遍历背包容量即可

先遍历物品 后遍历背包:组合

先遍历背包 后遍历物品:排列

牛逼!

518. Coin Change II

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp = [0 for _ in range(amount + 1)]
        dp[0] = 1
        for c in coins:
            for j in range(c, amount + 1):
                dp[j] = dp[j] + dp[j - c]
            # print(dp)
        return dp[-1]
        

377. Combination Sum IV

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0 for _ in range(target + 1)]
        dp[0] = 1

        for j in range(1, target + 1):
            for n in nums:
                if n <= j:
                    dp[j] = dp[j] + dp[j - n]
        return dp[-1]
        

322. Coin Change

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf') for _ in range(amount + 1)]
        dp[0] = 0

        for c in coins:
            for j in range(c, amount + 1):
                dp[j] = min(dp[j], dp[j - c] + 1)
        if dp[-1] == float('inf'):
            return -1
        return dp[-1]

279. Perfect Squares

class Solution:
    def numSquares(self, n: int) -> int:
        import math
        items = [i ** 2 for i in range(1, math.floor(math.sqrt(n)) + 1)]
        dp = [float('inf') for _ in range(n + 1)]
        dp[0] = 0

        for item in items:
            for j in range(1, n + 1):
                if j >= item:
                    dp[j] = min(dp[j], dp[j - item] + 1)
        return dp[-1]

139. Word Break

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False for _ in range(len(s) + 1)]
        dp[0] = True

        for j in range(1, len(s) + 1):
            for word in wordDict:
                if j >= len(word) and s[j - len(word): j] == word:
                    dp[j] = (dp[j] or dp[j - len(word)])
        return dp[-1]

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值