问题描述:https://leetcode-cn.com/problems/perfect-squares/description/
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...
)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n =12
输出: 3 解释:12 = 4 + 4 + 4.
解法1:数论知识:
定理1:
Lagrange 四平方定理: 任何一个正整数都可以表示成不超过四个整数的平方之和。
可以参考:https://blog.csdn.net/wenzhong003/article/details/49930361?fps=1&locationNum=4
那么这里只让输出这个组成的个数,所以必定是1 2 3 4中的一个,
1.若是1,直接判断是不是平方数即可;
2.对于4,还有定理
满足四数平方和定理的数n(这里要满足由四个数构成,小于四个不行),必定满足 n= 4^a(8b + 7)
因此,满足这种格式,必然是4。
3.对于2,可以采用穷举法:若n=a^2+b^2; 那么有2x=(a+b)^2+(a-b)^2; a,b都不超过sqrt(n);
4.上述都不是,那么就返回3了。
class Solution {
public:
int numSquares(int n) {
//1???
double s=sqrt(n);
int a=(int)(s);
if(a*a==n)
return 1;
//2???
for(int i=1; i<a+1; i++)
{
for(int j=1; j<a+1; j++)
{
if(i*i+j*j==n)
return 2;
}
}
//4???
int nn=n;
while(nn%4==0)
{
nn=nn>>2;
}
if((nn-7)%8==0)
return 4;
//3
return 3;
}
};
效率非常高,4ms。
方法2
通过动态规划方法:
其中dp[i]表示正整数i最少能由多个完全平方数组成,
一个正整数i,最多由i个1组成,所以将其初始化:dp[i] = i;
从1开始遍历i:对每一个平方数进行判断,如果i小于平方数,结束;如果i大于平方数,那么可能会出现更小的值:i-num值对应的最小个数加上(本身num)这1个平方数。
class Solution {
public:
int numSquares(int n) {
int *dp=new int[n+2];
int *ss=new int[n+2], scount=1;
int s=1;
int s1=0;
int s2=s*s;
for(int i=1; i<n+1; i++)
{
dp[i]=i;
if(i==s2)
{
dp[i]=1;
s1=s2;
s++;
s2=s*s;
ss[scount]=s1;
scount++;
} else if(i<s2)
{
for(int j=scount-1; j>1; j--)
{
dp[i]=min(dp[i],dp[ss[j]]+dp[i-ss[j]]);
}
}
cout<<dp[i]<<endl;
}
return dp[n];
}
};