leetcode No279 完全平方数 java

题目

在这里插入图片描述

题解

刚看到这道题的时候,我的直觉就告诉我,肯定有很巧妙的数学办法,但是左思右想还是没想出来,算了,还是先上普通的解法吧。

万变不离其‘背包’—完全背包 朴素解法

与昨天的每日一题非常相似(题目作标:No518 零钱兑换Ⅱ 题解作标:No518超基础全方位入门本题
这道题化成背包问题来看的话,背包问题的物品就是平方数(物品下标为i,体积为i*i), 背包容量就是给定的数字n。表中i 和 j 分别表示,考虑从1 到 i 这些数中取平方数(比如1、2、3取得为1、4、9),这些平方数以最少的数量相加得到 j ,这个数量为多少。(假设j = 12,i = 3时,dp[i][j] = 3,原因是:12 = 4 + 4 + 4,一共有 3 个 4 组成)

那么问题来了,i 我们该如何取值呢?
实际上,既然要前 i 个数的平方值组成 j 的话,那么最大值 i 的平方数就不可以超过j,因此边界条件为 i * i ≤ j。

假设n值为13,则因此dp表格为:
dp表格

注:dp[i][0]初始化为0很好理解,至于为什么dp[0][j]初始化为n的原因,先推出动态转移方程再细说 边界问题

本题推出动态转移方程的核心思想其一就是 dp[i][j] 中j这一项要大于0,现在我们来分步骤考虑:

  • 在dp[i][j]中,当不选择下标为i的平方数时,dp[i][j]结果为dp[i - 1][j](因为不考虑为i的这个数,所以dp[i][j]的答案肯定由前i - 1个数得出)
  • 在dp[i][j]中,当选择下标为 i 的平方数时,设 x 等于 i 的平方数(x = i * i),有如下情况:
    ①当取 1 个下标为i的平方数x时,情况为:dp[i][j] = dp[i - 1][j - x] + 1 (减掉1个x,剩余的值由前i - 1个数得出)
    ②当取 2 个下标为i的硬币时的情况为:dp[i][j] = dp[i - 1][j - x*2] + 2 (减掉2个x,剩余的值由前i - 1个数得出)
    ③当取 3 个下标为i的硬币时的情况为:dp[i][j] = dp[i - 1][j - x*3] + 3 (减掉3个x,剩余的值由前i - 1个数得出)
    … (令a = j - x*n ,要保证dp[i][a] 中的a是要大于0的)
    ④当取 m 个下标为i的硬币时的情况为:dp[i][j] = dp[i - 1][j - x*n] + m (减掉n个x,剩余的值由前i - 1个数得出)
    由上述可知,一共有n种情况,我们的dp[i][j]到底该取哪一种情况呢?题目要求我们要“最少能有多少平方数组成”,因此我们应该取这m种情况的最小值,即为:dp[i][j] = min( dp[i-1][j - x], dp[i-1][j - x * 2], … , dp[i - 1][j - x * m] )

将(选择当前下标 i 的情况)和(不选择当前下标 i 的情况)一起考虑,最终的动态转移方程为:
dp[i][j] = min( dp[i-1][j], dp[i-1][j - x] + 1, dp[i-1][j - x * 2] + 2, … , dp[i - 1][j - x * m] + m )
( j - x * m >= 0 )
得到的最终表为:
最终表
然后返回其dp[3][13]即可

边界问题 : 昨天经过小伙伴的提醒,我注意到初始化值这一块也需要注意注意这里解释一下为什么

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值