给你一个整数 n
,返回 和为 n
的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1
、4
、9
和 16
都是完全平方数,而 3
和 11
不是。
1 思路 动态规划
dp[i]为和为i的完全平方数的最少数量。
任意正整数n都是n个1的和,因此和为n的完全平方数的最少数量不超过n。
dp初始化:对于所有0<=i<=n,dp[i] = i。
动态规划边界情况dp[0] = 0。
当 i≥1 时,对于满足 1 ≤ j^2 ≤ i 的每个整数 j,都可以将 i 表示成 (i−j^2)+j^2,其中 j^2 是小于等于 i 的完全平方数,当 dp[i−j^2] 已知时,和为 i 的完全平方数的最少数量不超过 dp[i−j^2]+1,遍历所有的 j 之后即可得到 dp[i]。因此动态规划的状态转移方程是:对于所有满足 1≤j^2≤i 的整数 j,dp[i]=min{dp[i−j^2]}+1。
public class Solution {
public int NumSquares(int n) {
int[] dp = new int[n + 1];
for(int i = 0; i <= n; i++)
dp[i] = i;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j * j <= i; j++)
dp[i] = Math.Min(dp[i], dp[i - j * j] + 1);
}
return dp[n];
}
}
复杂度分析
-
时间复杂度:O(n * n^1/2),其中 n 是给定的整数。状态数是 O(n),每个状态的计算时间是 O(n),因此时间复杂度是 O(n * n^1/2)。
-
空间复杂度:O(n),其中 n 是给定的整数。需要创建长度为 n+1 的数组 dp。
2 四平方和定理
四平方和定理证明了任意一个正整数都可以被表示为至多四个正整数的平方和。这给出了本题的答案的上界。
public class Solution {
public 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;
}
// 判断是否为完全平方数
public bool IsPerfectSquare(int x) {
int y = (int) Math.Sqrt(x);
return y * y == x;
}
// 判断是否能表示为 4^k*(8m+7)
public bool CheckAnswer4(int x) {
while (x % 4 == 0) {
x /= 4;
}
return x % 8 == 7;
}
}