Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9
题意:给定一个整整数n,找出和为n且个数最少的平方数的个数。
1.动态规划
分析:这个题目类似于完全背包问题,设 x(i) = i * i, i为整整数,则满足:
目标函数: min(Σδ(i))
约束条件:
1. Σx(i) *δ(i) = n, i = 1, 2, 3 … sqrt(n);
2. δ(i) >= 0
我们考虑正整数为i的最优解minlen[i],假设i的最优解的平方和中有一个平方数数为 j(j <= n),那么minlen[i] - 1一定是i - j 的最优解,即minlen[i - j] = minlen[i] - 1。
证明:反证,假设minlen[i - j] = m < minlen[i] - 1, 则存在平方数j,使得 i - j + j = i, 即i的解为m + 1 < minlen[i] - 1 + 1 < minlen[i],这与假设minlen[i]为i的最优解矛盾。
状态转移方程:
minlen[i] = min(minlen[i - j * j] + 1) ,j * j <= n;
minlen[0] = 0;
具体代码:
class Solution {//cpp
public:
int numSquares(int n) {
vector<int> minlen(n + 1, n);
minlen[0] = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j * j <= i; j++){
if(minlen[i] > minlen[i- j * j] +1)
minlen[i] = minlen[i - j * j] + 1;
}
}
return minlen[n];
}
};
2.Lagrange 四平方定理
Lagrange 四平方定理: 任何一个正整数都可以表示成不超过四个整数的平方之和
关于这个定理的证明大家可以自行百度,因为我也不会0.0。
具体分析:
- 4n和n的平方数个数相同,即解相同。(eg: 3和12, 5和 20,这一步有利于大数变小数)
- n mod 8 = 7, 则 n只能表示成4个数的平方之和,即解为4。
对于解为1的情况,我们只需判断n是否为完全平方数,那么就只剩下解为2和为3的情况了。
具体代码如下:
class Solution {
public:
int numSquares(int n) {
while (n % 4 == 0) n /= 4;
int j = sqrt(n);
if(j * j == n) return 1;
if (n % 8 == 7) return 4;
for (int a = 1; a * a <= n; ++a) {
int b = sqrt(n - a * a);
if (a * a + b * b == n) {
return 2;
}
}
return 3;
}
};
参考链接:
1.http://www.changhai.org/articles/science/mathematics/four_square_theorem.php
2.http://www.lai18.com/content/1370786.html