题目
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
分析
- 先说我自己写的哦,我写的比较暴力,就是遍历了n的所有加数,取得他们的最小平方数个数,在这过程中用一个一维数组保存了一下中间量,免得重复计算,就这样,我虽然说是通过了,但是是1100+ms,也是很长时间了,再看前面的人,大都是2ms再不行是50ms左右。
是我时间复杂度太高了,然后看了下他们前面的代码,先看的是2ms左右的代码。
原来有一个定理,四平方和定理。
四平方和定理说明每个正整数均可表示为4个整数的平方和。
-
它还有一个公式,正好我们这道题可以用得上:
n = 4^k * ( 8*m +7)
那这样我们就可以根据这个公式来判断出n这个整数它的返回值是不是4,
当然n也有可能=3/2/1,判断完上面,我们继续筛选,n=2或1的情况也还是比较好判断的,判断n是不是等于两个平方数相加。筛选完2和1的情况,也不用判断就是3啦。 -
这个是用的公式,也并不能帮我改进我自己写的复杂度高的算法。
那下面这个就算是我的优化了:
我直接贴代码吧,其实我看得有些稀里糊涂
// 这是我寄几的
class Solution {
public int numSquares(int n) {
int[] minFactor = new int[n+1];
for (int i = 0; i < n+1; i++) {
minFactor[i] = Integer.MAX_VALUE;
}
for (int i = 1; i*i < n+1; i++) {
minFactor[i*i] = 1;
}
findMin(minFactor,n);
// print(minFactor);
return minFactor[n];
}
public static void findMin(int[] minFactor, int n){
for (int i = 1; i <= n/2; i++) {
int addnum = n - i;
if (minFactor[i] == Integer.MAX_VALUE){
findMin(minFactor,i);
}
if (minFactor[addnum] == Integer.MAX_VALUE)
findMin(minFactor,addnum);
minFactor[n] = Math.min(minFactor[n],minFactor[i]+minFactor[addnum]);
}
}
}
//这是优化的
class Solution {
public int numSquares(int n) {
int f[] = new int[n + 1];
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 2; i <= n; i++)
for (int j = 1; j * j <= i; j++)
f[i] = Math.min(f[i], f[i - j * j] + 1);
return f[n];
}
}
//这是用四平方定理的
class Solution {
public int numSquares(int n) {
while (n % 4 == 0) {
n /= 4;
}
if (n % 8 == 7) {
return 4;
}
for (int i = 0; i * i <= n; i++) {
int j = (int) Math.sqrt(n - i * i);
if (i * i + j * j == n) {
return i * j == 0 ? 1 : 2;
}
}
return 3;
}
}