题目链接:
题目描述:
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9
提示:
1 <= n <= 104
解题思路:
从小于等于n的完全平方数中取出特定的元素,且这些元素满足一定的条件(和为n),满足背包问题的描述
又每个平方数可以重复取,故为完全背包。平方数为物品,n为容量,dp[j]为凑成j的最少平方数的数量
dp四部曲:
确定dp数组:dp[j]表示凑成j的最少平方数的数量
确定递推公式:dp[j] = min(dp[j], dp[j - nums[i]] + 1),第一项是没考虑nums[i]的情况,第2项是考虑了nums[i]的情况
初始化dp数组:dp[0] = 0,题目中n>0,所以这里的dp[0]没有意义,只是作为递推公式成立的前提条件,其他dp值初始化为n(即组成n的平方数的最大数量,全1的情况),这样做的目的是让dp值可以被比较小的值覆盖
确定遍历顺序:这里求得是最小值,而只有在求组合或者排列数量时才对完全背包的内外层遍历顺序有要求,这里无特定要求。外层遍历物品,内层遍历容量或者反过来也行。下面代码采用前者
代码如下:
class Solution:
def numSquares(self, n: int) -> int:
dp = [n] * (n + 1)
dp[0] = 0
nums = (x*x for x in range(n) if x*x <= n)#因为物品只要遍历一次,所以可以用生成器生成,减小内存消耗
for i in nums:
for j in range(i, n + 1):
dp[j] = min(dp[j], dp[j - i] + 1)
return dp[n]