代码随想录算法训练营之JAVA|第三十八天|494. 目标和

今天是第38天刷leetcode,立个flag,打卡60天。

算法挑战链接

494. 目标和icon-default.png?t=N6B9https://leetcode.cn/problems/target-sum/

第一想法

题目理解:题目给出一个数组,使用 + 或 - 算术符号,有多少种组合可以得到target的值。

拿到题目的第一想法是使用回溯算法,因为可以挨个去尝试。如果将所有的结果都尝试了,就可以得出有多少种组合可以满足。

但是很不幸,超时了。

看完代码随想录之后的想法 

依旧是 0-1 背包问题的解决方案。

之前我做的0-1背包解决的问题是:容量为J的背包,价值最大的解决方案,和这个组合的好像是不相干的。的确也是,看完代码随想录之后,明白了,这个是0-1背包的变形。

跟着动态规划的五部曲走一遍,或许可以明白这个变形是怎么来的。

动态规划的五部曲走起:

  • 确定dp数组(dp table)以及下标的含义

dp[j] 代表的含义是:在 0-i 物品任取的情况下,价值为 J 的组合有 dp[j] 种

  • 确定递推公式

这个可以从开始递推。

假设数组是[0,1,2,3,4,5],target 5

取0的时候,有dp[5]种方式

取1的时候,有dp[4]种方式

取2的时候,有dp[3]种方式

取3的时候,有dp[2]种方式

取4的时候,有dp[1]种方式

取5的时候,有dp[0]种方式

如果不明白可以在想想 dp[j] 的含义。

那么dp[5] = dp[0] + dp[1] + dp[2] + dp[3] + dp[4] + dp[5]

那么抽象在代码中可以写成是:

dp[j] += dp[j - nums[i]]
  • dp的初始化

dp[0] = 1,解释一下为什么dp[0] 需要初始化为1。

其实不要硬去解释它的含义,咱就把 dp[0]的情况带入本题看看应该等于多少。

如果数组[0] ,target = 0,那么 bagSize = (target + sum) / 2 = 0。 dp[0]也应该是1, 也就是说给数组里的元素 0 前面无论放加法还是减法,都是 1 种方法。

所以本题我们应该初始化 dp[0] 为 1。

可能有同学想了,那 如果是 数组[0,0,0,0,0] target = 0 呢。

其实 此时最终的dp[0] = 32,也就是这五个零 子集的所有组合情况,但此dp[0]非彼dp[0],dp[0]能算出32,其基础是因为dp[0] = 1 累加起来的。

dp[j]其他下标对应的数值也应该初始化为0,从递推公式也可以看出,dp[j]要保证是0的初始值,才能正确的由dp[j - nums[i]]推导出来。

  • 确定遍历顺序

先遍历物品,然后在遍历容量,遍历容量的时候需要从大到小开始遍历,因为有每个物品只能使用一次的限制。

  • 举例推导dp数组

数据就不推导了。

今日收获

有些东西是会变化的,也许这个就是区分普通和厉害的一个很重要的点。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值