初见背包问题-递归方式

背包问题是选和不选思想的代表

0-1背包代码:

例题1

494. 目标和

给你一个非负整数数组 nums 和一个整数 target 。

向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 :

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

示例 2:输入:nums = [1], target = 1
输出:1

思想:添加正数和为p  负数-(s-p)target=p-(s-p) 所以 p=(s+target)/2

因此问题转变成从number选择一些数字,使得他们和等于(s+target)/2

1

问:dfs(i - 1, c) + dfs(i - 1, c - nums[i]) 中的加法是什么意思?

答:这叫加法原理,如果事件 A 和事件 B 是互斥的(即不能同时发生,不选 nums[i][的同时,又选了 nums【i】,那么发生事件 A 或事件 B 的总数等于事件 A 的数量加上事件 B 的数量

总结:至多装capacity,就把if c==0的判断删除

            至少装capacity,改成if c <=0.另外if c<nums[i]的判断也要删除

所以当题目要求恰好装capacity时,就是求方案数,用加法原理

class Solution:
    def findTargetSumWays(self, nums: List[int], target: int) -> int:
        target+=sum(nums)
        if target<0 or target%2:
            return 0
        target//=2

        n=len(nums)
        @cache
        def dfs(i,c):
            if i<0:
                return 1 if c==0 else 0
            if c<nums[i]:
                return dfs(i-1,c)
            return dfs(i-1,c)+dfs(i-1,c-nums[i])

        return dfs(n-1,target)

完全背包

322. 零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:

        n=len(coins)
        @cache
        def dfs(i,c):
            if i<0:
                return 0 if c==0 else inf
            if c<coins[i]:
                return dfs(i-1,c)
            return min(dfs(i-1,c),dfs(i,c-coins[i])+1)
        ans=dfs(n-1,amount)
        return ans if ans<inf else -1

分析:+1表示选了这个硬币,所以硬币个数加一,我们要求最少的,所以是min,如果dfs(i-1,c),dfs(i,c-coins[i])+1都不满足,返回值都是inf,因此输出前要判断ans的值是不是inf,是的话表示两种都不满足,返回-1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值