一、题目介绍
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...
)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n =12
输出: 3 解释:12 = 4 + 4 + 4.
示例 2:
输入: n =13
输出: 2 解释:13 = 4 + 9.
二、解题思路
该题有两种解决思路,第一种广度搜索优先的思想(BFS),第二种动态规划的思想。
(1)BFS:当每一次都可以有多种分支的时候,适合用广度搜索的方法。比如输入13,其下面可以有12-1*1=12、12-2*2 =9、12-3*3 = 4这三个分支,关系如下图所示
(2)动态规划:假设输入n时对应的最少完全平方数的个数为f(n)。如果n=4,则f(4)的最大值为4,即f(4) = 1+1+1+1。将f(4)初始化为最大值,如果已知f(3)的值,则有f(4) = min(f(4), f(3)+1),由此类推动态转移方程为 f(n) = min( f(n), f(n-1)+1)。
三、解题代码
第一种方法BFS:
int numSquares(int n) {
queue<int> que;
vector<bool> record(n+1, 0); //剪枝(记忆化)
que.push(n);
record[n] = 1;
int step = 0;
while(!que.empty())
{
int nlen = que.size();
step++;
int j = 0;
while(j < nlen)
{
int cur = que.front();
que.pop();
for(int i = 1; ; ++i)
{
int temp = (cur-i*i);
if(temp == 0) //说明找到解,返回当前的层数
return step;
else if(temp > 0 && record[temp] == 0) //判断当前的值是否已经求解过
{
record[temp] = 1;
que.push(temp);
}
else if(temp < 0) //如果当前值减去i*i小于0,则跳出循环
{
break;
}
}
++j;
}
}
return -1;
}
第二种方法动态规划:
int numSquares(int n) {
int* dp = new int[n+1]; //dp动态数组中保存每个1-n之间,每个正整数所对应的完全平方数的个数
dp[0] = 0;
for(int i = 1; i <= n; ++i)
{
dp[i] = i; //初始化为最大值
for(int j = 1; i - j*j >= 0; ++j)
{
dp[i] = min(dp[i], dp[i-j*j]+1); //动态转移方程
}
}
return dp[n];
}
四、解题结果
第一种方法的运行结果