来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/perfect-squares
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
动态规划,背包解法
参考: https://leetcode-cn.com/problems/perfect-squares/solution/hua-jie-suan-fa-279-wan-quan-ping-fang-shu-by-guan/
每个数都可以看做一个数和一个平方数的和,即 num = s + a^2,同理 s 也可以看做一个数和另一个平方数的和, 最糟糕的情况就是好多个1 相加等于自身
这里用一个数组将小于等于num 的每个数所需要的最少需要的平方数的个数记录下来,即每个数对应的最优解
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1]; // 默认初始化值都为0
for (int i = 1; i <= n; i++) {
dp[i] = i; // 最坏的情况就是每次+1
for (int j = 1; i - j * j >= 0; j++) {
dp[i] = Math.min(dp[i], dp[i - j * j] + 1); // 动态转移方程
}
}
return dp[n];
}
}
背包问题理解过程:
https://www.cnblogs.com/toone/p/8554817.html
还有一种方法
理论是:
拉格朗日四平方和定理
四平方和定理:每个正整数均可表示成4个整数的平方和。
注意有些整数不可表示为3个整数的平方和,例如7。
等价的说法是:每个正整数均可表示成不超过四个整数的平方之和。
重要推论:
-
数 n 只能表示成四个整数的平方和,不能表示成更少个数的平方和,必定满足 4a(8b+7).
-
如果 n%4==0,k=n/4,n 和 k 可由相同个数的整数表示
如何利用推论求一个正整数最少需要多少个数的平方和表示:
-
先判断这个数是否满足 4a(8b+7),如果满足,那么这个数就至少需要 4 个数的平方和表示。
-
如果不满足,再在上面除以 4 之后的结果上暴力尝试只需要 1 个数就能表示和只需要 2 个数就能表示的情况。
-
如果还不满足,那么就只需要 3 个数就能表示。
具体数学定理连接: https://www.cnblogs.com/lfri/p/11717745.html
代码:
链接:https://leetcode-cn.com/problems/perfect-squares/solution/python-3xing-dp-bfs-xiang-jie-by-knifezhu/
class Solution:
def numSquares(self, n: int) -> int:
while n % 4 == 0:
n /= 4
if n % 8 == 7:
return 4
a = 0
while a**2 <= n:
b = int((n - a**2)**0.5)
if a**2 + b**2 == n:
return bool(a) + bool(b)
a += 1
return 3