题目

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

数据

  1. 示例 1:
  2. 输入:
  3. 11110
  4. 11010
  5. 11000
  6. 00000
  7. 输出: 1
  8. 示例 2:
  9. 输入:
  10. 11000
  11. 11000
  12. 00100
  13. 00011
  14. 输出: 3
  15. 解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成

解题思路

used :哈希集合,用于判断节点是否入过队列;当节点加入队列时,同时将节点信息加入哈希集
numIslands :两层循环判断是否节点已经加入过队列,如果没有: nums++ ,把当前节点的下标传入 BFS ,加入哈希集 used
BFS :创建队列来进行广度优先搜索:队列头部的上下左右四个相邻节点是否满足条件,满足则加入队列和 used ,然后队列头部节点出队

代码

  1. package DataStructure;
  2. import java.util.HashSet;
  3. import java.util.LinkedList;
  4. import java.util.Queue;
  5. import java.util.Set;
  6. public class BFS {
  7. /**
  8. * Given a 2d grid map of '1's (land) and '0's (water), count the number of islands.
  9. * An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically.
  10. * You may assume all four edges of the grid are all surrounded by water.
  11. * Input:
  12. * 11110
  13. * 11010
  14. * 11000
  15. * 00000
  16. * Output: 1
  17. *
  18. * @param grid
  19. * @return the num of lands
  20. */
  21. public int numIslands(char[][] grid) {
  22. Set<Node> used = new HashSet<>(); //用于判定节点是否加入过队列
  23. int nums = 0;
  24. for (int i = 0; i < grid.length; i++) { // 遍历每个节点,如果节点为1并且不在哈希集中,则nums++,并把节点信息传给BFS
  25. for (int j = 0; j < grid[0].length; j++) {
  26. if (grid[i][j] == '1' && !used.contains(new Node(i, j))) {
  27. nums++;
  28. used.add(new Node(i, j));
  29. BFS(grid, i, j, used);
  30. }
  31. }
  32. }
  33. return nums;
  34. }
  35. /**
  36. * 为哈希集 used 配置每个节点的信息,存储节点下标
  37. */
  38. class Node {
  39. int x, y;
  40. public Node(int i, int j) {
  41. x = i;
  42. y = j;
  43. }
  44. @Override
  45. public boolean equals(Object obj) {
  46. if (!(obj instanceof Node))
  47. return false;
  48. if (obj == this)
  49. return true;
  50. return this.x == ((Node) obj).x && this.y == ((Node) obj).y;
  51. }
  52. @Override
  53. public int hashCode() {
  54. return x + y;
  55. }
  56. }
  57. /**
  58. * 对于每个队列头节点,遍历其相邻的节点,将所有相连节点加入队列
  59. *
  60. * @param grid
  61. * @param x
  62. * @param y
  63. * @param used
  64. */
  65. public void BFS(char[][] grid, int x, int y, Set<Node> used) {
  66. Queue<Node> queue = new LinkedList<>();
  67. queue.add(new Node(x, y));
  68. int length = grid.length;
  69. int width = grid[0].length;
  70. while (!queue.isEmpty()) { //相邻节点满足没有加入过队列且为陆地则入队,入集合used
  71. // 右边相邻节点
  72. int i = queue.peek().x, j = queue.peek().y + 1;
  73. if (j < width && grid[i][j] == '1' && !used.contains(new Node(i, j))) { //如果右边相邻的是陆地并且不在哈希集中,加入队列,加入哈希集
  74. queue.add(new Node(i, j));
  75. used.add(new Node(i, j));
  76. }
  77. // 下面相邻节点
  78. i = queue.peek().x + 1;
  79. j = queue.peek().y;
  80. if (i < length && grid[i][j] == '1' && !used.contains(new Node(i, j))) { //如果下面相邻的是陆地并且不在哈希集中,加入队列,加入哈希集
  81. queue.add(new Node(i, j));
  82. used.add(new Node(i, j));
  83. }
  84. //左边相邻节点
  85. i = queue.peek().x;
  86. j = queue.peek().y - 1;
  87. if (j >= 0 && grid[i][j] == '1' && !used.contains(new Node(i, j))) {
  88. queue.add(new Node(i, j));
  89. used.add(new Node(i, j));
  90. }
  91. // 上面相邻的节点
  92. i = queue.peek().x - 1;
  93. j = queue.peek().y;
  94. if (i >= 0 && grid[i][j] == '1' && !used.contains(new Node(i, j))) {
  95. queue.add(new Node(i, j));
  96. used.add(new Node(i, j));
  97. }
  98. queue.poll();
  99. }
  100. }
  101. }