算法刷题笔记:搜索
基本技巧
广度优先搜索
常用 queue 作为队列
1 |
|
常在计算最短路径时使用,拥有比 DFS 更好的时间复杂度
深度优先搜索
常用递归函数解决
剪枝策略:
- 最优剪枝策略:当当前计算的答案已经不可能更优时,直接停止计算
标记技巧
在求路径时,一定要注意标记,避免重复走某一个的情况:
- DFS 在进入下一个函数前标记
- BFS 在进入队列的同时进行标记
在二维平面上做标记不一定得用二维数组,也可以用多个一维数组来表示下标为 i 的占用情况:
用数组解决“往周围格子走”
1 | for (int i=0;i<4;i++){ |
八皇后问题
棋子不能出现在同一行同一列以及同一对角线( k = 1 和 k = -1 的直线)
难点:标记占用的格子,如果直接用二维数组进行标记,会导致确定是否有标记时 时间复杂度较高
解决方法:
- 用一个一维数组 c[i],若 c[i] 为 1 表示第 i 列已经有占用的了
- 用一个一维数组 d[i],若 d[i] 为 1 表示 的对角线已被占用(即通过 中的截距 来定位唯一的对角线)
- 用一个一维数组 e[i],若 e[i] 为 1 表示 的对角线已被占用(即通过 中的截距 来定位唯一的对角线),此处加 n 是为了保证结果为正
1 | void search(int r) { |
障碍迷宫问题
简单的 DFS 问题,但要注意一些处理的技巧和易错的细节。
处理技巧:
-
二维数组多开两行两列并初始化为障碍(常用 1 表示),这样可以避免判断边界情况
1
2
3
4
5
6for (i = 0; i <= n+1; i ++) {
g[i][0] = g[i][m + 1] = 1;
}
for (i = 0; i <= m+1; i ++) {
g[0][i] = g[n+1][i] = 1;
}
易错细节:
- 终止条件除了到达终点之外,还有 x 和 y 坐标是否小于 0 或超过最大值、是否遇到障碍、是否已经访问过
- 在退出一个 dfs 函数前,需要进行回溯,即将访问过的标记还原为未访问