一、思路
看到可以取一个数的随机个数凑成一个特定值的时候,我们就应该想到 [完全背包] 问题。
如果不能,现在就要开始培养这种习惯:
这个问题并没有给出可以选择的完全平方数数组,所以我们需要将可以使用的完全平方数数字列出来促成一个可供选择的数字数组 [nums] ,从而就与 [完全背包] 有异曲同工之妙。看到题目目标值最大为10000,所以完全平方数的最大值为100,将1-100放入nums数组中。最后这个题就转化为从 [nums] 中选取凑成目标值的最少数字个数,每个数字可以无限使用。
二、解法
(1)、确定dp数组及其下标含义:dp[j]:和为j的完全平方数的最少数量
(2)、确定递推公式:凑成目标值为 j-nums[i] 的最少个数是 dp[j-nums[i]] ,然后再加上一个数字nums[i]就能够凑成目标值 j 。所以dp[j]=dp[j-coins[i]]+1。
递推公式:dp[j]=min(dp[j-coins[i]]+1,dp[j])。
(3)、初始化dp数组:
凑成目标值为0的个数为0,所以dp[0]=0;其他位置直接设置为INT_MAX,防止在取到最小值的时候被初始值覆盖。
三、代码
class Solution {
public:
int numSquares(int n) {
vector<int> nums(101,0);
for(int i=0;i<=100;i++)
{
nums[i]=i*i;
}
vector<int> dp(n+1,INT_MAX);
dp[0]=0;
for(int i=1;i<nums.size()&&n>=nums[i];i++)
{
for(int j=nums[i];j<=n;j++)
{
dp[j]=min(dp[j-nums[i]]+1,dp[j]);
}
}
return dp[n];
}
};
复杂度分析
时间复杂度:O(n*√n),其中n为给定的整数,状态转移方程的时间复杂度为O(√n),共计算n个状态,所以时间复杂度为O(n*√n)。
空间复杂度:O(101+n)。nums数组空间长度为101,dp数组的空间长度为n。