题目
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, …) which sum to n.
Example 1:
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.
Example 2:
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.
Solution 1 动态规划
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, INT_MAX);
dp[0] = 0;
for (int i = 1; i < n+1; i++) {
for (int j = 1; j * j <= i; j++) {
dp[i] = min (dp[i], dp[i - j * j] + 1);
}
}
return dp[n];
}
}
建立一个数组,每一位所存的都是对应下标数字n的最小的平方和的数目, 也就是说dp[i] = numSquares(i)
。
这个数组可以从0开始计算,我们已知numSquares(i)=0
,因此dp[0]=0
。
对于之后的每一个数i
,我们都计算是否存在x
和j
使得
i
=
x
+
j
2
i = x + j^2
i=x+j2 。
如果存在:
- 那么我们就可以得知,
dp[i]
可以等于dp[x]+1
,因为i
可以表示成x
的平方和形式(dp[i]
个)再加上 j 2 j^2 j2(1个)。 - 当然,如果本身(
dp[i]
)比这个值(dp[x]+1
)小的话,我们当然选择不变。
这样,我们计算到dp[n]
的时候,也就得到了我们的解。
Solution 2 超秀的纯数学解法
class Solution {
public:
int numSquares(int n) {
int maxSq = sqrt(n);
if (isSquare(n)) return 1;
int tmp = n;
while (tmp % 4 == 0) tmp /= 4;
if (tmp % 8 == 7) return 4;
for (int i = 0; i <= maxSq; i++) {
if ( isSquare (n - i*i) ) return 2;
}
return 3;
}
bool isSquare(int n) {
float maxSq = sqrt(n);
if (abs(maxSq - (int)maxSq) < 10e-5) return true;
return false;
}
};
主要用到的数学公式有两个,一个是四平方和定理(Lagrange’s four-square theorem),一个是三平方和定理(Legendre’s three-square theorem)。
四平方和说的是:任意一个正整数可以表示成少于等于4个平方数的和。
这个定理使得我们可以确定我们的返回值只会有1、2、3、4四种情况。即Answer <= 4
。
三平方和说的是:当且仅当一个正整数不符合 4 k ( 8 b + 7 ) 4^k(8b+7) 4k(8b+7) 的形式时,这个正整数可以表示成少于等于3个平方数的和。
所以我们可以对每种结果分情况考虑了:
Answer = 1
:我们可以简单的判断一个数是不是平方数,是的话返回1
。Answer = 4
:通过三平方定理判断是否Answer > 3
,若成立那么Answer = 4
。Answer = 2
:简单的for
循环判断是否为2个数的平方和。Answer = 3
:1、4、2
都排除就剩下Answer = 3
了。