算法题——深度优先搜索与广度优先搜索
Posted xiaolou的每日生活
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法题——深度优先搜索与广度优先搜索相关的知识,希望对你有一定的参考价值。
深度优先搜索和广度优先搜索作为应用广泛的搜索算法,一般是各大公司招聘的必考算法,可能面试官会当场让你手写一个深度优先搜索算法题,所以今天我们来重点讲解深度优先搜索和广度优先搜素算法:
深度优先算法(DFS):
不断地沿着顶点的深度方向进行遍历,该算法的空间复杂度与数据结构深度成正比;
广度优先算法(BFS):
先访问完当前顶点的所有邻接点,然后再访问下一层的所有节点,该算法适用于解决最短、最小路径等问题,但是构建广度优先算法需要维护自己的队列。
题目一:给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。Leetcode.111
解题思路:直接利用递归的方式处理二叉树的左右节点,并比较左右子节点的最小深度,选择小的那个子节点深度再加一,即可得到该节点的最小深度。
程序实现:
class Solution {
//广度优先遍历
public int minDepth(TreeNode root) {
if(root == null) return 0;
int left = minDepth(root.left);
int right = minDepth(root.right);
if(left == 0 || right == 0)
return left + right + 1;
return Math.min(left, right) + 1;
}
}
题目二:给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。Leetcode. 279
解题思路:可将该问题转化为图论问题——从n到0,每个数表示一个节点,如果两个数相差一个完全平方数,则将其连接起来,从而能够得到一个无权图,再根据这个无权图找到n到0的最短路径。对于转化后问题的描述,我们知道需要求的是图的最短路径,那么可以利用BFS来实现。
程序实现:
class Solution {
public int numSquares(int n){
Queue<Integer> queue = new LinkedList<>();
Set<Integer> set = new HashSet<>();
int dist = 0;
queue.offer(0);
set.add(0);
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0; i < size; i++){
int front = queue.poll();
if(n == front) return dist;
for(int j = 1; j * j + front < n; j++){
int temp = j * j + front;
if(set.add(temp)) queue.offer(temp);
}
}
dist++;
}
return -1;
}
}
题目三:有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
解题思路:为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程,将所有有记录的像素点的颜色值改为新的颜色值。通过上述描述,我们观察到可以利用DFS实现该过程。
程序实现:
class Solution{
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
int col = image.length;
int row = image[0].length;
if(col == 0 || row == 0) return image;
int oldColor = image[sr][sc];
if(oldColor == newColor) return image;
//实现dfs过程
image[sr][sc] = newColor;
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
for(int i = 0; i < 4; i++){
int x = sr + dx[i];
int y = sc + dy[i];
if(x >= 0 && x < col && y >= 0 && y < row && image[sr][sc] == oldColor)
floodFill(image, x, y, newColor);
}
return image;
}
}
题目四:给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例:
输入:
11110
11010
11000
00000
输出: 1
解题思路:根据DFS可有效解决此题,遍历二维网格其中一个点周围的水平方向和垂直方向点,如果这些点都是‘1’,则将其作为一个区域。继续遍历,直到遇见‘0’为止。
程序实现:
class Solution {
public int numIslands(char[][] grid) {
int res = 0;
if(grid.length == 0 || grid[0].length == 0)
return 0;
int col = grid.length;
int row = grid[0].length;
for(int i = 0; i < col; i ++){
for(int j = 0; j < row; j++){
if(grid[i][j] == '1'){
res++;
dfs(grid, i, j);
}
}
}
return res;
}
public void dfs(char[][] grid, int col, int row){
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
grid[col][row] = '0';
for(int i = 0; i < 4; i ++){
int x = col + dx[i];
int y = row + dy[i];
if(x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == '1')
dfs(grid, x, y);
}
}
}
题目五:给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。
示例:
输入:
X X X X
X O O X
X X O X
X O X X
X X X X
X X X X
X X X X
X O X X
解题思路:
本题可以用DFS(深度优先搜索)解决。
找到所有被X围绕的区域不容易,但是其等价于找到所有没有没有被X围绕的区域(连接边界的区域),这样就可以从边界上的O开始进行深度优先搜索,
举个例子:
X X X X
X X O X
X O X X
X O X X
对于上面这张图的边界,只有第四行第二列的内容是O,我们对其进行DFS,即DFS(3,1) 首先将它本身改为#
X X X X
X X O X
X O X X
X # X X
之后对该位置的上下左右进行搜索,即分别尝试DFS(2,1),DFS(4,1),DFS(3,0),DFS(3,2),如果越界或者内容不是O则停止搜索。因为此位置左右是X,下面超出数组下边界,只有上面是O,所以继续进行DFS(2,1)。
X X X X
X X O X
X # X X
X # X X
和之前一样,先将其本身改为#,之后上下左右进行DFS,而对于此坐标上下左右都不是O,所以搜索结束。最后遍历全图,将所有的#改为O,所有的O改为X即可。
程序实现:
class Solution{
public void solve(char[][] grid){
if(grid.length == 0 || grid[0].length == 0)
return;
int col = grid.length;
int row = grid[0].length;
for(int i = 0; i < col; i++){
if(grid[0][i] == 'O') dfs(grid, 0, i);
if(grid[row-1][i] == 'O') dfs(grid, row-1, i);
}
for(int i = 0; i < row; i++){
if(grid[i][0] == 'O') dfs(grid, i, 0);
if(grid[i][col-1] == 'O' dfs(grid, i, col-1);
}
for(int i = 0; i < col; i++){
for(int j = 0; j < row; j++){
if(grid[i][j] == '#')
grid[i][j] = 'O';
if(grid[i][j] == 'O')
grid[i][j] = 'X';
}
}
}
public void dfs(char[][] grid, int sc, int sv){
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
grid[sc][sv] = '#'
for(int i = 0; i < 4; i++){
int x = sc + dx[i];
int y = sv + dy[i];
if(x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == 'O')
dfs(grid, x, y);
}
}
}
以上是关于算法题——深度优先搜索与广度优先搜索的主要内容,如果未能解决你的问题,请参考以下文章
数据结构与算法图遍历算法 ( 深度优先搜索 DFS | 深度优先搜索和广度优先搜索 | 深度优先搜索基本思想 | 深度优先搜索算法步骤 | 深度优先搜索理论示例 )