今天周末,心血来潮打开LeetCode做一道题:
https://leetcode-cn.com/problems/number-of-enclaves/
看到题,我的第一想法是:
从边缘的陆地开始,找到它的最大连通区域。找到的连通区域设置标记位,避免找重复。所有边缘陆地的连通区域都找完以后,没有被标记的陆地就是飞地。
找连通区域,是图的深度优先搜索和广度优先搜索的经典问题。
- 识别图上的起点。这里四条边的每个陆地都是起点。将它们保存到队列中。
- 通过深度优先搜索,构建一个陆地的连通图。
- 通过广度优先搜索,构建一个陆地的连通图。
由于队列中所有符合条件的陆地起点(四个边上的陆地),所以遍历到最后,可以获得所有的陆地连通图。
深度优先搜索
从起点出发,沿着一条边搜索,直到到达终点,得到一条完整的边。这时再回到上一次分叉的起点。进行下一条边的搜索。这种回到分叉点,意味着要用先入后出的栈结构。
广度优先搜索
从起点出发,将它的相邻节点放到队列中。再找这些节点的相邻节点。直到找到所有的相邻节点。
不管是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