完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4
示例 2:
输入:n = 13
输出:2
解释:13 = 4 + 9
动态规划
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1];
Arrays.fill(dp, 100000);
dp[0] = 0;
int sqrt = (int)Math.sqrt(n);
int[] squares = new int[sqrt + 1];
for (int i = 1; i <= sqrt; i++)
squares[i] = i * i;
for (int i = 1; i <= n; i++) {
sqrt = (int)Math.sqrt(i);
for (int j = 1; j <= sqrt; j++)
dp[i] = Math.min(dp[i], dp[i - squares[j]] + 1);
}
return dp[n];
}
}
贪心枚举
class Solution {
private Set<Integer> square_nums = new HashSet<Integer>();
public int numSquares(int n) {
for (int i = 1; i * i <= n; ++i)
square_nums.add(i * i);
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
private boolean is_divided_by(int n, int count) {
if (count == 1)
return square_nums.contains(n);
for (int square : square_nums) {
if (is_divided_by(n - square, count - 1))
return true;
}
return false;
}
}
BFS
class Solution {
public int numSquares(int n) {
int sqrt = (int)Math.sqrt(n);
int[] square_nums = new int[sqrt + 1];
for (int i = 1; i * i <= n; i++)
square_nums[i] = i * i;
Set<Integer> visited = new HashSet<Integer>();
Queue<Integer> queue = new LinkedList<Integer>();
queue.offer(0);
int count = 0;
while (!queue.isEmpty()) {
count++;
int size = queue.size();
while (size-- > 0) {
int sum = queue.poll();
for (int i = 1; i <= sqrt; i++) {
int num = sum + square_nums[i];
if (num == n) {
return count;
} else if (num > n) {
break;
} else if (!visited.contains(num)) {
visited.add(num);
queue.offer(num);
}
}
}
}
return -1;
}
}
数学方法
四平方和定理:每个自然数都可以表示为四个整数平方和
n
=
a
0
2
+
a
1
2
+
a
2
2
+
a
3
2
n=a_{0}^{2}+a_{1}^{2}+a_{2}^{2}+a_{3}^{2}
n=a02+a12+a22+a32
三平方和定理:
n
≠
4
k
(
8
m
+
7
)
⟺
n
=
a
0
2
+
a
1
2
+
a
2
2
n \ne 4^{k}(8m+7) \iff n = a_{0}^{2}+a_{1}^{2}+a_{2}^{2}
n=4k(8m+7)⟺n=a02+a12+a22
因此,我们可以使用三平方和定理来判断 平方和的个数是否为4。
class Solution {
private boolean isSquare(int n) {
int sqrt = (int) Math.sqrt(n);
return n == sqrt * sqrt;
}
public int numSquares(int n) {
if (isSquare(n))
return 1;
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
for (int i = 1; i * i <= n; ++i) {
if (isSquare(n - i * i))
return 2;
}
return 3;
}
}
有效的完全平方数
给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
示例 1:
输入:num = 16
输出:true
示例 2:
输入:num = 14
输出:false
二分查找
class Solution {
public boolean isPerfectSquare(int num) {
int end = Math.min(46340, num / 2 + 1);
return binarySearch(num, 1, end);
}
private boolean binarySearch(int target, int start, int end) {
while (start <= end) {
int mid = start + (end - start) / 2;
int num = mid * mid;
if (target == num)
return true;
else if (target < num)
end = mid - 1;
else
start = mid + 1;
}
return false;
}
}
牛顿迭代法
x k + 1 = 1 2 ( x k + num x k ) x_{k + 1} = \frac{1}{2}\left(x_k + \frac{\textrm{num}}{x_k}\right) xk+1=21(xk+xknum)
class Solution {
public boolean isPerfectSquare(int num) {
if (num < 2)
return true;
long x = num / 2;
while (x * x > num)
x = (x + num / x) / 2;
return x * x == num;
}
}