深度优先搜索与广度优先搜索区别和案例

今天周末,心血来潮打开LeetCode做一道题:
https://leetcode-cn.com/problems/number-of-enclaves/
看到题,我的第一想法是:
从边缘的陆地开始,找到它的最大连通区域。找到的连通区域设置标记位,避免找重复。所有边缘陆地的连通区域都找完以后,没有被标记的陆地就是飞地。

找连通区域,是图的深度优先搜索和广度优先搜索的经典问题。

  1. 识别图上的起点。这里四条边的每个陆地都是起点。将它们保存到队列中。
  2. 通过深度优先搜索,构建一个陆地的连通图。
  3. 通过广度优先搜索,构建一个陆地的连通图。

由于队列中所有符合条件的陆地起点(四个边上的陆地),所以遍历到最后,可以获得所有的陆地连通图。

深度优先搜索

从起点出发,沿着一条边搜索,直到到达终点,得到一条完整的边。这时再回到上一次分叉的起点。进行下一条边的搜索。这种回到分叉点,意味着要用先入后出的栈结构

广度优先搜索

从起点出发,将它的相邻节点放到队列中。再找这些节点的相邻节点。直到找到所有的相邻节点。

不管是DFS还是WFS,为保证所有的节点被搜索,按照固定的顺序(节点有三个子节点,从左到右或者从右到左依次处理)进行搜索。

Java的ArrayDeque

java.util.ArrayDeque,既可以作为栈结构,也可以作为队列结构。

ArrayDeque作为堆栈

要在Java中实现LIFO(后进先出)堆栈,建议在Stack类上使用双端队列。该ArrayDeque类比Stack类快。

ArrayDeque 提供了以下可用于实现堆栈的方法。

push() - 在堆栈顶部添加一个元素

peek() - 从堆栈顶部返回一个元素

pop() - 返回并从堆栈顶部删除元素

ArrayDeque作为队列

ArrayDeque是一个双端队列。
将元素插入双端队列
1.使用add(),addFirst()和addLast()添加元素。满了抛异常IllegalStatementException

add() - 将指定的元素插入ArrayDeque双端队列的末尾

addFirst() -在双端队列的开头,插入指定的元素

addLast() - 在双端队列的末尾插入指定的内容(等效于add())

2 使用remove() ,removeFirst()和removeLast() 返回并删除元素。如果没有可以删除的元素抛异常IllegalStatementException。其中remove等同于removeFirst

3 使用 offer(),offerFirst()和offerLast()插入元素。offer返回并在队尾插入元素,如果插入失败,返回false。

4 使用 poll() pollFirst pollLast删除元素。poll返回并删除双端队列的第一个元素。pollFirst等同于poll。

add和offer从队尾插入元素,失败的情况下add会抛异常。
remove和poll从队首删除元素,失败的情况下remove会抛异常。

DFS和WFS的题解

DFS用ArrayDeque作为栈:方法offer和poll
WFS用ArrayDeque作为队列:方法push和pop
(即取出的是最先放进去的还是最后放进去的元素。

DFS

package graph.connected_land;

import java.util.ArrayDeque;

public class Dfs {
    static class Solution {
        int [][] neighbors = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
        public int numEnclaves(int[][] grid) {
            int rows = grid.length;
            int cols = grid[0].length;
            ArrayDeque<int[]> searched = new ArrayDeque<int[]>();
            boolean[][] visited = new boolean[rows][cols];
            for (int i = 0; i < rows; i++) {
                if (grid[i][0] == 1) {
                    searched.push(new int[]{i, 0});
                    visited[i][0] = true;
                }
                if (grid[i][cols-1] == 1) {
                    searched.push(new int[]{i, cols-1});
                    visited[i][cols-1] = true;
                }
            }
            for (int i=1; i < cols-1; i++ ) {
                if (grid[0][i] == 1) {
                    searched.push(new int[]{0, i});
                    visited[0][i] = true;
                }
                if (grid[rows-1][i] == 1) {
                    searched.push(new int[]{rows-1, i});
                    visited[rows-1][i] = true;
                }
            }
            while(!searched.isEmpty()) {
                int[] c = searched.pop();
                for (int[] neighbor : neighbors) {
                    int x = c[0] + neighbor[0];
                    int y = c[1] + neighbor[1];
                    System.out.println("x " + x + "y " + y);
                    if (x < 0 || x > rows-1 || y < 0 || y > cols-1 || visited[x][y] ){
                        continue;
                    }
                    if (grid[x][y] == 1) {
                        searched.push(new int[]{x, y});
                        visited[x][y] = true;
                    }
                }

            }
            int count = 0;
            for (int i = 1; i< rows-1; i++) {
                for (int j = 1; j < cols-1; j++) {
                    if (grid[i][j] == 1 && visited[i][j] == false) {
                        count++;
                    }
                }
            }
            return count;
        }
    }
}

WFS

package graph.connected_land;

import java.util.ArrayDeque;
import com.sun.jmx.remote.internal.ArrayQueue;

/*

 */
public class Wfs {


    static class Solution {
        int [][] neighbors = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
        public int numEnclaves(int[][] grid) {
            int rows = grid.length;
            int cols = grid[0].length;
            ArrayDeque<int[]> searched = new ArrayDeque<int[]>();
            boolean[][] visited = new boolean[rows][cols];
            for (int i = 0; i < rows; i++) {
                if (grid[i][0] == 1) {
                    searched.offer(new int[]{i, 0});
                    visited[i][0] = true;
                }
                if (grid[i][cols-1] == 1) {
                    searched.offer(new int[]{i, cols-1});
                    visited[i][cols-1] = true;
                }
            }
            for (int i=1; i < cols-1; i++ ) {
                if (grid[0][i] == 1) {
                    searched.offer(new int[]{0, i});
                    visited[0][i] = true;
                }
                if (grid[rows-1][i] == 1) {
                    searched.offer(new int[]{rows-1, i});
                    visited[rows-1][i] = true;
                }
            }
            while(!searched.isEmpty()) {
                int[] c = searched.poll();
                for (int[] neighbor : neighbors) {
                    int x = c[0] + neighbor[0];
                    int y = c[1] + neighbor[1];
                    System.out.println("x " + x + "y " + y);
                    if (x < 0 || x > rows-1 || y < 0 || y > cols-1 || visited[x][y] ){
                        continue;
                    }
                    if (grid[x][y] == 1) {
                        searched.offer(new int[]{x, y});
                        visited[x][y] = true;
                    }
                }

            }
            int count = 0;
            for (int i = 1; i< rows-1; i++) {
                for (int j = 1; j < cols-1; j++) {
                    if (grid[i][j] == 1 && visited[i][j] == false) {
                        count++;
                    }
                }
            }
            return count;
        }
    }
}

测试数据

public static void main(String[] args) {
        int[][] grid = {{0,0,0,0},{1,0,1,0},{0,1,1,0},{0,0,0,0}};
        int[][] grid2 = {{0,1,1,0},{0,0,1,0},{0,0,1,0},{0,0,0,0}};
        int[][] grid3 = {
            {0,0,1,1,1,0,1,1,1,0,1},
            {1,1,1,1,0,1,0,1,1,0,0},
            {0,1,0,1,1,0,0,0,0,1,0},
            {1,0,1,1,1,1,1,0,0,0,1},
            {0,0,1,0,1,1,0,0,1,0,0},
            {1,0,0,1,1,1,0,0,0,1,1},
            {0,1,0,1,1,0,0,0,1,0,0},
            {0,1,1,0,1,0,1,1,1,0,0},
            {1,1,0,1,1,1,0,0,0,0,0},
            {1,0,1,1,0,0,0,1,0,0,1}};
        Wfs.Solution solution = new Wfs.Solution();
        System.out.println(solution.numEnclaves(grid3));
    }

链接

题目
https://leetcode-cn.com/problems/number-of-enclaves/

深度优先搜索与广度优先搜索的本质区别!
https://zhuanlan.zhihu.com/p/74472146

Java ArrayDeque
https://www.cainiaojc.com/java/java-arraydeque.html

你可能感兴趣的:(深度优先,宽度优先,算法)