leetcode No279 完全平方数 java

题目

leetcode No279 完全平方数 java_第1张图片

题解

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

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

与昨天的每日一题非常相似(题目作标: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表格为:
leetcode No279 完全平方数 java_第2张图片

注: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 )
得到的最终表为:
leetcode No279 完全平方数 java_第3张图片
然后返回其dp[3][13]即可

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

你可能感兴趣的:(LeetCode刷题,动态规划,java,算法,数据结构,编程语言)