BFS 和 DFS
对比:
BFS
- 空间是指数级别的 大(O(a^n))
- 不会有爆栈的风险,因为该内存可以从堆中申请
- 可以搜最小(短)
DFS
- 空间和深度成正比 小(O(n))
- 有爆栈的风险,比如树的深度最坏可能有 10万层
- 不能搜最小(短)
实际编程中:
BFS:代码较多,需要维护一个队列
DFS:代码简单,需要不断递归
例题 1:
279. 完全平方数
思路:
- 初始点:0,如果加 1,状态从 0 转移到 1,如果加 4,状态从 0 转移到 4;在此基础上加 9,状态从 4 到 13;所以转移到 1,需要 1 步,转移到 13,需要 2 步
- 所以抽象成图论。从一个状态转移到另一个状态,边的权值为 1。状态就是从 1 到 n,求解的过程就是从 i 点 到 j 点转移的次数
- 需要让组成和的完全平方数的个数最少。我们从以上给出 DFS 和 BFS 性质可知,此题应用 BFS
#include<iostream>
#include <vector>
#include <string>
#include <queue>
using namespace std;
class solution
{
public:
int numSquares(int n)
{
queue<int> q;
vector<int> dist(n + 1, INT_MAX);
q.push(0);
dist[0] = 0;
while (q.size())
{
int t = q.front();
q.pop();
if (t == n) return dist[t];
for (int i = 1; i*i + t <= n; i++)
{
int j = t + i*i;
if (dist[j] > dist[t] + 1)
{
dist[j] = dist[t] + 1;
q.push(j);
}
}
}
return 0;
}
};
int main()
{
solution s;
cout << s.numSquares(12);
system("pause");
return 0;
}
代码解析:
-
记录状态,即当前应从哪一个点出发,同时宽搜后,下一次可以达到多个状态,也需要将其保存,以便不断循环执行代码,找到结果。
利用一个队列,保存状态信息
第一次赋初值
0 第二次循环
先弹出状态 0,相当于从 0 点出发
在满足条件下,保存从状态 0 出发可以转移到的状态
1 4 9 第三次循环
先弹出状态 1,相当于从 1 点出发
在满足条件下,保存从状态 1 出发可以转移到的状态
4 9 2 5 10 以此类推
-
还需要有一个矩阵来维护从状态 i 到状态 j 转移的最小步数(最小边),dist
dist 矩阵,下标为状态,对应存储的值为最小转移步数
利用上述每次需要遍历的状态(从 queue 中获取),通过计算,将结果存入 dist 中
第一次:
int t = q.front(); q.pop();
t = 0,可以转移到的状态所需步数如下,同时将其存入 queue 中
0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 +∞ +∞ 1 +∞ +∞ +∞ +∞ 1 +∞ +∞ +∞ 第二次:
t = 1
0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 +∞ 1 2 +∞ +∞ +∞ 1 2 +∞ +∞ 第三次:
t = 4
0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 +∞ 1 2 +∞ +∞ 2 1 2 +∞ +∞ 以此类推,结果:
0 1 2 3 4 5 6 7 8 9 10 11 12 0 1 2 3 1 2 3 4 2 1 2 3 3