279. 完全平方数
一、题目描述
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
示例 1:
输入: n = 12 输出: 3 解释: 12 = 4 + 4 + 4.
示例 2:
输入: n = 13 输出: 2 解释: 13 = 4 + 9.
二、题解
一、解题思路
对问题建模:
整个问题转化为一个图论问题。
从n到0,每个数字表示一个节点;
如果两个数字x到y相差一个完全平方数,则连接一条边。
我们得到了一个无权图。
原问题转化成,求这个无权图从n到0的最短路径。
| n | 解释 | 个数 |
|---|---|---|
| 1 | 1-->0 | 1 |
| 2 | 1-->1-->0 | 2 |
| 3 | 3-->2-->1-->0 | 3 |
| 4 | 4-->0 | 1 |
| 5 | 5-->1-->0 | 2 |
| 6 | 6-->2-->1-->0 | 3 |
| 7 | 7-->3-->2-->1-->0 | 4 |
| 8 | 8-->4-->0 | 2 |
| 9 | 9-->0 | 1 |

二、代码
public int numSquares(int n) {
Queue<Pair<Integer, Integer>> queue = new ArrayDeque<>();
queue.add(new Pair<>(n, 0));
//访问标志的数组 进行路径优化
// 提前已经访问的节点即可证明之前路径比此路径短
boolean[] visited = new boolean[n + 1];
visited[n] = true;
while (!queue.isEmpty()) {
int num = queue.peek().getKey();
int step = queue.peek().getValue();
queue.poll();
for (int i = 1; ; i++) {
int temp = num - i * i;
if (temp < 0) break;
if (temp == 0) return step + 1;
if (!visited[temp]) {
//该数之前已访问 通过此线的路径 绝不是最短路径
// 则可以不用将后续的节点入队列
queue.add(new Pair<>(temp, step + 1));
visited[temp] = true;
}
}
}
return -1;
} 
京公网安备 11010502036488号