题目
链接: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.
BFS
本题等价于求最短路径的问题。将每个整数当成一个树的节点,下一个节点值为当前节点值减去在平方数列表squares
中的一个值,这样就能形成一棵树,当下一个节点值为0时说明找到了一种平方数的组合,通过BFS可以求得最短路径,也就是求得最短得组合大小。
class Solution {
public int numSquares(int n) {
// 1.构建平方数的集合
List<Integer> squares = new ArrayList<>();
for (int i = 1; i * i <= n; i++) {
squares.add(i*i);
}
// 2. 将整数看成一个节点如果两个整数相减为一个平方数
// ,则两个整数所在节点存在一条边
boolean[] seen = new boolean[n + 1];
Queue<Integer> queue = new LinkedList<>();
queue.offer(n);
seen[n] = true;
int level = 0;
while (!queue.isEmpty()) {
level++;
int size = queue.size();
while (size-- > 0) {
int cur = queue.poll();
for (Integer num : squares) {
int next = cur - num;
if (next < 0) // 由于是递增的后面的next节点全部小于0
break;
if (next == 0)
return level;
if (seen[next])
continue;
seen[next] = true;
queue.offer(next);
}
}
}
return n;
}
}
动态规化
假设n为5
0:0
1:1
2:1+1
3: 1+1+1
4: 1+1+1+1 、 4
5: 1+4、1+1+1+1
-
设置状态:
设dp[i]
为构成数字i所需要的最少完全平方数的个数,dp[0] = 0
-
确定状态转移方程:
d p [ i ] = m i n ( d p [ i − k ] + 1 ) ; k 为 不 超 过 i 的 完 全 平 方 数 dp[i] = min(dp[i-k]+1) ; k 为不超过i的完全平方数 dp[i]=min(dp[i−k]+1);k为不超过i的完全平方数
class Solution {
public int numSquares(int n) {
List<Integer> squares = new ArrayList<>();
for (int i = 1; i * i <= n; i++) {
squares.add(i*i);
}
// 设置状态dp[i]表示数字够成数字i所使用的完全平方数的个数, dp[0] = 0
int[] dp = new int[n+1];
for (int i = 1; i <= n; i++) {
int min = Integer.MAX_VALUE;
for (Integer square : squares) {
if (square > i)
break;
min = Math.min(min, dp[i - square]+1);
}
dp[i] = min;
}
return dp[n];
}
}