562. 背包问题 IV

写在前面,如果有更好的方法可以给博主分享一下么,木有vip,看不到lintcode的题解,谢谢啦

题目描述

https://www.lintcode.com/problem/backpack-iv/description

给出 n 个物品, 以及一个数组, nums[i]代表第i个物品的大小, 保证大小均为正数并且没有重复, 正整数 target 表示背包的大小, 找到能填满背包的方案数。
每一个物品可以使用无数次

样例1

输入: nums = [2, 3, 6, 7] 和 target = 7

输出: 2

解释:

方案有:

[7]

[2, 2, 3]

样例2

输入: nums = [2, 3, 4, 5] 和 target = 7

输出: 3

解释: 

方法有:

[2, 5]

[3, 4]

[2, 2, 3]

题解

方法一: 递归

递归,暴力穷举所有可能性,没啥可说的很容易理解。解释一下这一段,由于递归的时候传递的是i而不是i+1,是因为题目中可以重复取(即下次递归的时候还可以继续取用i),然后某一轮递归结束,回到该i时,因为target-nums[i]小于零(取过后面的值),则会跳过该i,即不取用。

for i in range(index, len(nums)):
            if target - nums[i] >= 0 :
                res += self._helper(nums, i, target - nums[i])
class Solution:
    """
    @param nums: an integer array and all positive numbers, no duplicates
    @param target: An integer
    @return: An integer
    """
    def __init__(self):
        self.memo = []

    def backPackIV(self, nums, target):
        # write your code here
        if not nums or target <= 0:
            return 0
        return self._helper(nums, 0, target)

    def _helper(self, nums, index, target):
        if index >= len(nums) or target < 0:
            return 0
        if target == 0:
            return 1
        res = 0
        for i in range(index, len(nums)):
            if target - nums[i] >= 0 :
                res += self._helper(nums, i, target - nums[i])
            # 下面注释掉是因为,其实不取即取0次,已经包含进上面了,直接跳过去了
            # res += self._helper(nums, i + 1, target)
        return res

方法二:记忆化搜索

由递归到记忆化搜索很水到渠成

class Solution:
    """
    @param nums: an integer array and all positive numbers, no duplicates
    @param target: An integer
    @return: An integer
    """
    def __init__(self):
        self.memo = []

    def backPackIV(self, nums, target):
        # write your code here
        if not nums or target <= 0:
            return 0
        self.memo = [[-1] * (target + 1) for _ in range(len(nums))]
        return self._helper(nums, 0, target)

    def _helper(self, nums, index, target):
        if index >= len(nums) or target < 0:
            return 0
        if target == 0:
            return 1
        if self.memo[index][target] != -1:
            return self.memo[index][target]
        res = 0
        for i in range(index, len(nums)):
            if target - nums[i] >= 0 :
                res += self._helper(nums, i, target - nums[i])
        self.memo[index][target] = res
        return res

方法三:动态规划

解释一下:times - 是最多可以取用i的次数,time=0表示不取用,times是可重复的标志

for i in range(1, len(nums)):
    for j in range(target + 1):
        # 下面的注释掉,是因为当time=0时,就是不去用i
        # dp[i][j] = dp[i-1][j]
        # times - 是最多可以取用i的次数,time=0表示不取用,times是可重复的标志
        times = j // nums[i]
        for time in range(0, times + 1):
            dp[i][j] += dp[i - 1][j - time * nums[i]]
class Solution:
    """
    @param nums: an integer array and all positive numbers, no duplicates
    @param target: An integer
    @return: An integer
    """
    def backPackIV(self, nums, target):
        # write your code here
        if not nums or target <= 0:
            return 0

        dp = [[0] * (target + 1) for _ in range(len(nums))]
        for j in range(target + 1):
            if j % nums[0] == 0:
                dp[0][j] = 1

        for i in range(1, len(nums)):
            for j in range(target + 1):
                # dp[i][j] = dp[i-1][j]
                times = j // nums[i]
                for time in range(0, times + 1):
                    dp[i][j] += dp[i - 1][j - time * nums[i]]

        return dp[-1][-1]

空间上的优化

与0-1背包类似,只不过这边要加如所有的可能性(因为可重复,[0,times])

for i in range(1, len(nums)):
    for j in range(target, -1, -1):
        times = j // nums[i]
        dp[j] = sum([dp[j - time * nums[i]] for time in range(0, times + 1)])
        # for time in range(1, times + 1):
            # dp[j] += dp[j - time * nums[i]]
class Solution:
    """
    @param nums: an integer array and all positive numbers, no duplicates
    @param target: An integer
    @return: An integer
    """
    def backPackIV(self, nums, target):
        # write your code here
        if not nums or target <= 0:
            return 0

        dp = [0] * (target + 1)
        for j in range(target + 1):
            if j % nums[0] == 0:
                dp[j] = 1

        for i in range(1, len(nums)):
            for j in range(target, -1, -1):
                times = j // nums[i]
                dp[j] = sum([dp[j - time * nums[i]] for time in range(0, times + 1)])
                # for time in range(1, times + 1):
                #     dp[j] += dp[j - time * nums[i]]

        return dp[-1]

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值