1、动态规划法
我们可以利用数组dp记录每个数字对应完全平方数的最少数量。显然,为了找到每个数字对应的最少数量,我们需要遍历每一种可能,即 d p [ i ] = min j = 1 j ≤ i ( 1 + d p [ i − j 2 ] ) dp[i]=\min_{j=1}^{j\le \sqrt{i}}( 1+dp[i-j^2]) dp[i]=minj=1j≤i(1+dp[i−j2])。因此,我们只需要从小到大循环遍历i即可获得最终结果。
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1);
for (int i = 1; i <= n; i++) {
int minn = INT_MAX;
for (int j = 1; j * j <= i; j++) {
minn = min(minn, dp[i - j * j]);
}
dp[i] = minn + 1;
}
return dp[n];
}
};
2、数学
四平方和定理证明了任意一个正整数都可以被表示为至多四个正整数的平方和。同时四平方和定理包含了一个更强的结论:当且仅当 n ≠ 4 k × ( 8 m + 7 ) n\ne 4^k\times (8m+7) n=4k×(8m+7)时,n可以被表示为至多三个正整数的平方和;当 n = 4 k × ( 8 m + 7 ) n=4^k\times (8m+7) n=4k×(8m+7)时,n只能被表示为四个正整数的平方和。显然:1、当n为完全平方数时,答案为1;2、当 n = a 2 + b 2 n=a^2+b^2 n=a2+b2时,显然为2;3、排除法可得剩下的数字组合数为3。因此我们可以遍历每一种情况寻找其可能性。
class Solution {
public:
// 判断是否为完全平方数
bool isPerfectSquare(int x) {
int y = sqrt(x);
return y * y == x;
}
// 判断是否能表示为 4^k*(8m+7)
bool checkAnswer4(int x) {
while (x % 4 == 0) {
x /= 4;
}
return x % 8 == 7;
}
int numSquares(int n) {
if (isPerfectSquare(n)) {
return 1;
}
if (checkAnswer4(n)) {
return 4;
}
for (int i = 1; i * i <= n; i++) {
int j = n - i * i;
if (isPerfectSquare(j)) {
return 2;
}
}
return 3;
}
};