广度优先搜索具体操作是一层一层地进行遍历, 每层遍历都是以上一层遍历到的节点作为起点, 遍历其能访问到的所有节点. 需要注意的是, 遍历过的节点不能被再次遍历. 如下:
第一层: 0 -> {6, 2, 1, 5};
第二层: 6 -> {4}; 2 -> {}; 1 -> {}; 5 -> {3}
第三层: 4 -> {}; 3 -> {}
每一层遍历的节点到根节点的距离都相同. 假设 di 表示第 i 个节点与根节点的距离, 可以推导出一个结论: 对于先遍历的节点 i 与后遍历的节点 j, 有 di <= dj. 利用这个结论, 可以求解最短路径等 最优解 问题, 即第一次遍历到目标节点时, 所经过的路径为最短路径.
1. 完全平方
给定正整数 n, 找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n. 你需要让组成和的完全平方数的个数最少.
我们可以对问题进行抽象: 将 n 当做一个节点, 和其相连的节点是与其相差一个完全平方数的数, 如下所示, 我们就可以得到一个无权图(可能更像一个多叉树), 这样原问题就转化为: 求这个无权图中从 n 到 0 的最短路径, 使用广度优先搜索.
n = 7
6 3
5 2 2
4 1 1 1
0 0 0 0下面使用代码实现 BFS , 需要额外考虑的是:
使用队列: 存储遍历到的节点.
使用布尔数组: 标记遍历过的节点, 防止重复遍历.
public int numSquares(int n) {
if (n == 0) return 0;
Queue<Integer> queue = new ArrayDeque<>();
boolean[] visited = new boolean[n + 1]; // 标记当前节点是否访问过
// 从n点出发寻找最短路径, 当前步数为0
queue.add(n);
visited[n] = true;
int depth = 0;
while (!queue.isEmpty()) {
depth++; // 步数加一
int size = queue.size(); // 上一层的节点数
// 以上一层遍历到的节点作为起点
while (size-- > 0) {
int cur = queue.poll();
// 遍历其能访问到的所有节点
for (int i = 1; i * i <= cur; i++) {
int next = cur - i * i;
// 走到节点0找到最短路径, 返回步数
if (next == 0) return depth;
// 若当前节点之前访问过, 则跳过(若再走, 步数一定大于之前访问的步数)
if (visited[next]) continue;
visited[next] = true;
queue.add(next);
}
}
}
// n的组成除1外无其他完全平方数
return n;
} Note: 上述解法是标准的bfs模板, 利用queue.size()得到每一层的节点数并进行遍历, 同时也方便记录当前节点所在层数. 当遍历到目标节点时, 层数即为最短路径.

京公网安备 11010502036488号