完全平方数 题解
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/perfect-squares
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4
class Solution {
public int numSquares(int n) {
// 思路:BFS,将整数(如13)和与之差为完全平方数的数(如9)视作节点,其差视为边
// 故此,简化为从正整数n到0的最短路径(13→9(4)→0(3))
int res=0;
if (n==1) return 1;
Queue<Integer> queue=new LinkedList<>();
queue.add(n);
while(!queue.isEmpty()){
res++;
int queueSize=queue.size();
while(queueSize-->0){
int target=queue.poll();
for(int i=(int)Math.sqrt(target);i>0;i--){
int diff=target-i*i;
if (diff==0) return res;
if(diff>=1) queue.add(diff);
}
}
}
return -1;
}
}
改进:统一计算完全平方数(感觉没什么提升),标记访问过的节点
class Solution {
public int numSquares(int n) {
int res=0;
if (n==1) return 1;
Queue<Integer> queue=new LinkedList<>();
List<Integer> squares=generateSquares(n);
boolean[] marked = new boolean[n + 1];
marked[n] = true;
queue.add(n);
while(!queue.isEmpty()){
res++;
int queueSize=queue.size();
while(queueSize-->0){
int target=queue.poll();
for(int square:squares){
int diff=target-square;
if (diff==0) return res;
if (diff<0) break;
if(marked[diff]) continue;
marked[diff]=true;
queue.add(diff);
}
}
}
return -1;
}
private List<Integer> generateSquares(int n) {
List<Integer> squares = new ArrayList<>();
int square = 1;
int diff = 3;
while (square <= n) {
squares.add(square);
square += diff;
diff += 2;
}
return squares;
}
}
该题还可使用动态规划求解。使用dp数组记录前n-1个数的最小完全平方和个数;
遍历小于n的完全平方数,从dp[i-square]中获得最小的完全平方组合。
class Solution {
public int numSquares(int n) {
int res=0;
if (n==1) return 1;
Queue<Integer> queue=new LinkedList<>();
List<Integer> squares=generateSquares(n);
int[] dp=new int[n+1];
for(int i=1;i<=n;i++){
int min=i;
for(int square :squares){
if (square>i) break;
min=Math.min(min,dp[i-square]+1);
}
dp[i]=min;
}
return dp[n];
}
private List<Integer> generateSquares(int n) {
List<Integer> squares = new ArrayList<>();
int square = 1;
int diff = 3;
while (square <= n) {
squares.add(square);
square += diff;
diff += 2;
}
return squares;
}
}