代码随想录算法训练营第三十三天| 322. 零钱兑换、 279.完全平方数、139.单词拆分

写代码的第三十三天
有点点懂了,但是不多。。。。。。60%吧
呜呜呜呜呜

322. 零钱兑换

思路

因为每个硬币的数量是无限的,所以是一个完全背包问题。
解决问题1:dp[j]是什么含义?凑成总和为j的最少硬币个数。
解决问题2:递推公式是什么?两种情况,当前位置的coin用还是不用,如果用那么dp[j]的值就是dp[j-coin[i]]+1,因为我们这个题问的是硬币个数,所以在选用当前coin的时候应该+1;如果不选当前位置的coin,那么硬币个数还是dp[j],本题要的是最小硬币个数,所以应该是min(dp[j],dp[j-coin[i]]+1).
解决问题3:dp值的初始化为多少?当总和j为0的时候,能用多少个硬币呢?0个,所以dp[0]=0,其他的值我们要初始化为最大情况,因为本题要求的是最小数量。
解决问题4:遍历顺序是什么?本题只要求最少硬币个数,所以不用管组合还是排列,先遍历哪个都行。
解决问题5:输出dp数组。
错误第一版:没有考虑当没有能组成amount的情况。

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

正确代码

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        for i in range(len(coins)):
            for j in range(coins[i],amount+1):
                dp[j] = min(dp[j],dp[j-coins[i]]+1)
        if dp[amount] == float('inf'):
            return -1
        else:
            return dp[amount]

279.完全平方数

思路

之前的题已经给出了每个物品的重量或者value的数组,本题中没给,这个就是本题和上一个题的区分之处。
解决问题1:dp[j]是什么含义?凑成总和为j的最少完全平方数的个数。
解决问题2:递推公式是什么?两种情况,当前位置的数字用还是不用,如果用那么dp[j]的值就是dp[j-完全平方数(ii)]+1,因为我们这个题问的是完全平方数的个数,所以在选用当前数字的时候应该+1;如果不选当前位置的数字,那么最少个数还是dp[j],本题要的是最小完全平方数的个数,所以应该是min(dp[j],dp[j-ii]+1).
解决问题3:dp值的初始化为多少?当总和j为0的时候,能用多少个硬币呢?0个,所以dp[0]=0,其他的值我们要初始化为最大情况,因为本题要求的是最小数量。
解决问题4:遍历顺序是什么?本题只要求最少硬币个数,所以不用管组合还是排列,先遍历哪个都行。我选择了先遍历背包,因为物品的数量不确定,物品的数量是由当前背包容量j的开根号的最大整数决定的,也就是物品的数量最大值是根号j的最大整数。
解决问题5:输出dp数组。
正确代码

class Solution:
    def numSquares(self, n: int) -> int:
        dp = [float('inf')] * (n + 1)
        dp[0] = 0
        for j in range(1, n + 1):
            for i in range(1, int(math.sqrt(j)) + 1):
                dp[j] = min(dp[j], dp[j - i*i] + 1)
        return dp[n]

139.单词拆分

思路

本题要求单词可以重复使用,所以是完全背包问题,本题中s为背包容量,wordDict为物品。
解决问题1:dp[j]是什么含义?是否能凑成字符串j,如果可以是True,否则是False。
解决问题2:递推公式是什么?两种情况,当前位置的字符串用还是不用,如果用那么dp[j]的值就是dp[j-strs[i]];如果不选当前位置的数字,那么最少个数还是dp[j],所以应该是(dp[j]或dp[j-strs[i]]).
解决问题3:dp值的初始化为多少?当字符串j为空的时候,有能组成的字符串吗?必须的是True,没有任何实际意义,只是为了后续推导。
解决问题4:遍历顺序是什么?本题没有特殊要求,所以不用管组合还是排列,先遍历哪个都行。
解决问题5:输出dp数组。
错误第一版:使用 str[word] 来获取单词 word 的长度,应该使用 len(word) 来获取单词 word 的长度。另外,在动态规划更新中,应该考虑当前单词 word 是否和字符串 s 的某一部分匹配,而不是直接使用 dp[i - len(word)]。这样才能正确更新动态规划数组。

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

正确代码

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        dp = [False] * (len(s) + 1)
        dp[0] = True
        for j in range(1,len(s)+1):
            for word in wordDict:
                if j >= len(word):
                    dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
        return dp[len(s)]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值