目录
解法一:动态规划
对于一个数n来说,要求完全平方数的数量,它的完全平方数必然在区间 (根号下n需要向下取整)。那么对于在这个区间内的数 m,必然满足
在这种情况下,n的完全平方数的数量(用 f(n) 表示)为:
要求最少的数量,那就要比较这个区间里的所有元素,找出一个最少的来,所以,令表示正整数n的最少数量的完全平方和。则
其中m=sqrt(n)向下取整。
c++代码:
class Solution {
public:
int numSquares(int n) {
int f[n+1];
memset(f,0, sizeof(f));
f[0] = 0;
f[1] = 1;
for(int i = 2; i <= n; i++){
int m = sqrt(i);
int min = 9999;
for(int j = 1; j <= m; j++){
int tmp = f[i-j*j] + 1;
if(min > tmp){
min = tmp;
}
}
f[i] = min;
}
return f[n];
}
};
解法二:四平方和定理
定理内容:每个正整数均可表示成不超过四个整数的平方之和。
重要的推论:一个正整数 n, 如果只能被表示成四个整数的平方和,必定满足:
定理的证明:https://zhuanlan.zhihu.com/p/104030654
定理的内容以及推论:https://blog.csdn.net/l_mark/article/details/89044137
解决方案:
要求最少数量,根据分析只存在四种情况,最少数量m = 1,2,3,4。
- 判断m=1的情况,也就是n=a*a。
- 判断m=4的情况,也就是判断式子是否成立。
- 判断m=2的情况,也就是n=a*a+b*b。遍历区间1 <= i <= sqrt(n),判断n-i*i是否是完全平方数,如果是,则m=2。
- 其余情况,m=3。
class Solution {
public:
int numSquares(int n) {
int t = sqrt(n);
if(t*t == n) return 1; //判断m=1
t = n;
while(t % 4 == 0){
t = t / 4;
}
t = t % 8;
if(t == 7) return 4; //判断m=4
int m = sqrt(n);
for(int i = 1; i <= m; i++){
int a = i * i;
int b = sqrt(n-a);
if(b*b == (n-a)) return 2; //判断m=3
}
return 3; //其余情况m=3
}
};
下面是执行记录,第一个是解法二的,第二个是解法一的。