DFS(深度优先搜索)
这道题说的是一个机器人从左上角开始,他可以沿着上下左右四个方向走,并且走到的每个格子坐标的数字和不大于k,问可以走多少个格子。我们先来画个图看一下
这里统计的是能走多少个格子,所以统计肯定是不能有重复的,题中说了,机器人是可以沿着上下左右四个方向走的。但你想一下,任何一个格子你从任何一个方向进来(比如从上面进来),那么他只能往其他3个方向走,因为如果在往回走就重复了。但实际上我们只要沿着两个方向走就可以了,一个是右边,一个是下边,也就是上面图中红色的箭头。我们来看下代码
public int movingCount(int threshold, int rows, int cols) { //临时变量visited记录格子是否被访问过 boolean[][] visited = new boolean[rows][cols]; return dfs(0, 0, rows, cols, threshold, visited); } public int dfs(int i, int j, int rows, int cols, int threshold, boolean[][] visited) { //i >= rows || j >= cols是边界条件的判断,threshold < sum(i, j)判断当前格子坐标是否 // 满足条件,visited[i][j]判断这个格子是否被访问过 if (i >= rows || j >= cols || threshold < sum(i, j) || visited[i][j]) return 0; //标注这个格子被访问过 visited[i][j] = true; //沿着当前格子的右边和下边继续访问 return 1 + dfs(i + 1, j, rows, cols, threshold, visited) + dfs(i, j + 1, rows, cols, threshold, visited); } //计算两个坐标数字的和 private int sum(int i, int j) { int sum = 0; //计算坐标i所有数字的和 while (i != 0) { sum += i % 10; i /= 10; } //计算坐标j所有数字的和 while (j != 0) { sum += j % 10; j /= 10; } return sum; }
时间复杂度:O(m*n),最坏情况下,每个格子都走一遍
空间复杂度:O(m*n),需要二维数组visited记录每个格子是否被访问过
看一下运行结果
BFS(广度优先搜索)
DFS是沿着一个方向一直往下走,有一种不撞南墙不回头的感觉,直到不满足条件才会回头。而BFS就显得有点博爱了,他不是一条道走下去,他会把离他最近的都访问一遍,访问完之后才开始访问第二近的……,一直这样下去,所以最好的一种数据结构就是使用队列,因为队列是先进先出,离他最近的访问完之后加入到队列中,最先入队的也是最先出队的,代码和上面有很多相似的地方,基本上没什么难度,来看下,代码中有详细的注释
import java.util.LinkedList; import java.util.Queue; public class Solution { public int movingCount(int threshold, int rows, int cols) { //临时变量visited记录格子是否被访问过 boolean[][] visited = new boolean[rows][cols]; int res = 0; //创建一个队列,保存的是访问到的格子坐标,是个二维数组 Queue<int[]> queue = new LinkedList<>(); //从左上角坐标[0,0]点开始访问,add方法表示把坐标 // 点加入到队列的队尾 queue.add(new int[]{0, 0}); while (queue.size() > 0) { //这里的poll()函数表示的是移除队列头部元素,因为队列 // 是先进先出,从尾部添加,从头部移除 int[] x = queue.poll(); int i = x[0], j = x[1]; //i >= rows || j >= cols是边界条件的判断,threshold < sum(i, j)判断当前格子坐标是否 // 满足条件,visited[i][j]判断这个格子是否被访问过 if (i >= rows || j >= cols || threshold < sum(i, j) || visited[i][j]) continue; //标注这个格子被访问过 visited[i][j] = true; res++; //把当前格子右边格子的坐标加入到队列中 queue.add(new int[]{i + 1, j}); //把当前格子下边格子的坐标加入到队列中 queue.add(new int[]{i, j + 1}); } return res; } //计算两个坐标数字的和 private int sum(int i, int j) { int sum = 0; //计算坐标i所有数字的和 while (i != 0) { sum += i % 10; i /= 10; } //计算坐标j所有数字的和 while (j != 0) { sum += j % 10; j /= 10; } return sum; } }
时间复杂度:O(m*n),最坏情况下,每个格子都要记录
空间复杂度:O(m*n),需要二维数组visited记录每个格子是否被访问过
看一下运行结果
做这道题之前首先要明白DFS和BFS是什么意思,才能使用这两种方式。我们来画个图看一下
假如从A点开始访问,DFS就是沿着一条道走下去,然后再走其他的道……。BFS就是图中先访问圈内的部分,然后再把圈放大继续访问……。
截止到目前我在公众号“数据结构和算法”中已经写了500多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载
下载链接:https://pan.baidu.com/s/1hjwK0ZeRxYGB8lIkbKuQgQ
提取码:6666