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

算法训练营精选题解

1.322. 零钱兑换

题目链接:322. 零钱兑换
文档讲解: 代码随想录

(1)确定数组和下标
dp[ j ]表示凑成总金额为 j 最少需要的硬币数
(2)递推关系式
dp[ j ] = min(dp[ j ], dp[ j - coin[ i ]] + 1)
(3)初始化
dp[0] = 0,其余位置因为会比较取最小值,初始化为’inf’
(4)遍历顺序
组合的完全背包(?),先物品后背包,都从前往后
(5)打印数组

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        coins.sort()
        for i in range(len(coins)):
            if coins[i] <= amount: #可以不用加这个判断条件
                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]

注意点:本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以!但我认为这道题是求最少硬币数量,无关顺序,所以还是觉得是组合问题。

2.279.完全平方数

题目链接:279.完全平方数
文档讲解: 代码随想录

(1)确定数组和下标
dp[ j ] 表示和为 j 的最少完全平方数
(2)递推关系式
dp[ j ] = min(dp[ j ], dp[ j - i ] + 1),i 是遍历的完全平方数
(3)初始化
dp[0] = 0,其他取’inf’
(4)遍历顺序
无关顺序,按照组合完全背包,先物品后背包
(5)打印数组

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp = [float('inf')] * (n + 1)
        dp[0] = 0
        for i in range(1, int(n ** 0.5) + 1):
            for j in range(i * i, n + 1):
                dp[j] = min(dp[j], dp[j - i * i] + 1)
        return dp[n]

3.139.单词拆分

题目链接:139.单词拆分
文档讲解: 代码随想录

(1)确定数组和下标
dp[ i ]表示字符串长度为 i,是否可以拆分为一个或者多个在字典中出现的单词
(2)递推关系式
如果区间[j,i]区间内的子串出现在字典里并且dp[j] = True,那么dp[i] = True
(3)初始化
dp[0] = True,因为是递推的根基,否则后面都为False
(4)遍历顺序
因为单词可以重复出现,所以是完全背包问题。这道题求的是排列数,因为单词需要按照顺序排列才能组成字符串 s
(5)打印数组

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        #查找效率更高,set时间复杂度为o(1),而list为o(n)
        wordSet = set(wordDict)
        n = len(s)
        dp = [False] * (n + 1)
        dp[0] = True
        #排列,先背包后物品
        for i in range(1, n + 1):
            for j in range(i):
                if dp[j] and s[j:i] in wordSet:
                    dp[i] = True
                    break
        return dp[n]
class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: 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 s[j - len(word): j] == word)
        return dp[len(s)]
class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        #按照单词长度排序
        wordDict.sort(key = lambda x: len(x))
        dp = [False] * (len(s) + 1)
        dp[0] = True
        for j in range(1, len(s) + 1):
            for word in wordDict:
                #剪枝
                if len(word) > j:
                    break
                dp[j] = dp[j] or (dp[j - len(word)] and s[j - len(word):j] == word)
        return dp[-1]

4.多重背包

题目链接:多重背包
文档讲解: 代码随想录

C, M = [int(x) for x in input().split()]
weight = [int(x) for x in input().split()]
value = [int(x) for x in input().split()]
nums = [int(x) for x in input().split()]

dp = [0] * (C + 1)
for i in range(M):
    #背包倒序
    for j in range(C, weight[i] - 1, -1):
        for k in range(1, nums[i] + 1):
            if k * weight[i] > j:
                break
            dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i])
print(dp[C])

卡码网一直显示超时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值