99. 岛屿数量
思路:
遍历每个地方,如果该处为陆地,且未访问过。将结果加 1.并将该处所连的陆地全部标记为已访问。
方法一:
dfs ——先格子赋值为 true,再进入 dfs 函数。(dfs 隐式终止条件)
(实质是遍历相邻的 4 个节点)
import java.util.*;
public class Main {
public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0;
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
result++;
visited[i][j] = true; // 先赋值为 true,再进入 dfs 函数
dfs(grid, visited, i, j);
}
}
}
System.out.println(result);
}
public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
for (int i = 0; i < 4; i++) {
int nextX = dir[i][0] + x;
int nextY = dir[i][1] + y;
if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
continue;
}
if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) { // 必须是未访问过的陆地,递归终止条件隐含在此
visited[nextX][nextY] = true; // 先赋值为 true,再进入 dfs 函数
dfs(grid, visited, nextX, nextY);
}
}
}
}
方法二:
dfs ——判断完终止条件后,再赋值为 true。(dfs 显式终止条件)
(实质是从当前节点开始)
import java.util.*;
public class Main {
public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0;
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
result++;
dfs(grid, visited, i, j);
}
}
}
System.out.println(result);
}
public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
if (grid[x][y] == 0 || visited[x][y]) { // 当不是陆地或者已经访问过就退出
return;
}
visited[x][y] = true; // 判断完终止条件后,再赋值为 true
for (int i = 0; i < 4; i++) {
int nextX = dir[i][0] + x;
int nextY = dir[i][1] + y;
if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
continue;
}
dfs(grid, visited, nextX, nextY); // 不用判断陆地和访问,直接 dfs
}
}
}
方法三:
bfs
重点:队列刚一放进去元素,visited 数组就要立马标记为 true。
import java.util.*;
public class Main {
public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0;
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
result++;
bfs(grid, visited, i, j);
}
}
}
System.out.println(result);
}
public static void bfs(int[][] grid, boolean[][] visited, int x, int y) {
Queue<int[]> queue = new ArrayDeque<>();
queue.offer(new int[] {x, y});
visited[x][y] = true; // 队列刚一放进去元素,visited 数组就要立马标记为 true
while (!queue.isEmpty()) {
int[] cur = queue.poll();
for (int i = 0; i < 4; i++) {
int nextX = dir[i][0] + cur[0];
int nextY = dir[i][1] + cur[1];
// 判断未越界
if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
continue;
}
// 判断为陆地,且未访问过
if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) {
queue.offer(new int[] {nextX, nextY});
visited[nextX][nextY] = true; // 队列刚一放进去元素,visited 数组就要立马标记为 true
}
}
}
}
}
优化:
dfs 或 bfs 时,可以只搜右下的格子。
100. 岛屿的最大面积
思路和上题几乎一样,dfs 和 bfs 皆可,只需要把统计岛屿数量改成统计岛屿最大面积。
方法一:
dfs ——先格子赋值为 true,再进入 dfs 函数。(dfs 隐式终止条件)
(实质是遍历相邻的 4 个节点)
import java.util.*;
public class Main {
public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public static int count; // 统计单块区域面积
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0; // 统计最大面积
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
count = 1; // 初始化为 1
visited[i][j] = true; // 先赋值为 true,再进入 dfs 函数
dfs(grid, visited, i, j);
result = Math.max(result, count);
}
}
}
System.out.println(result);
}
public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
for (int i = 0; i < 4; i++) {
int nextX = dir[i][0] + x;
int nextY = dir[i][1] + y;
if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
continue;
}
if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) { // 必须是未访问过的陆地,递归终止条件隐含在此
count++; // 先 ++,再进入 dfs
visited[nextX][nextY] = true; // 先赋值为 true,再进入 dfs 函数
dfs(grid, visited, nextX, nextY);
}
}
}
}
方法二:
dfs ——判断完终止条件后,再赋值为 true。(dfs 显式终止条件)
(实质是从当前节点开始)
import java.util.*;
public class Main {
public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public static int count; // 统计单块区域面积
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0; // 统计最大面积
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
count = 0; // 因为是先进入 dfs 再 count++,所以这里要赋值为 0
dfs(grid, visited, i, j);
result = Math.max(result, count);
}
}
}
System.out.println(result);
}
public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
if (grid[x][y] == 0 || visited[x][y]) { // 当不是陆地或者已经访问过就退出
return;
}
count++; // 先进入 dfs 再 count++
visited[x][y] = true; // 先进入该格子再赋值为 true
for (int i = 0; i < 4; i++) {
int nextX = dir[i][0] + x;
int nextY = dir[i][1] + y;
if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
continue;
}
dfs(grid, visited, nextX, nextY); // 不用判断陆地和访问,直接 dfs
}
}
}
方法三:
以上两种 dfs 方法二合一。进入格子后立即赋为 true
import java.util.*;
public class Main {
public static int[][] dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
public static int count; // 统计单块区域面积
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = 0; // 统计最大面积
boolean[][] visited = new boolean[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
count = 1; // 初始化为 1
dfs(grid, visited, i, j);
result = Math.max(result, count);
}
}
}
System.out.println(result);
}
public static void dfs(int[][] grid, boolean[][] visited, int x, int y) {
visited[x][y] = true; // 进入后立即设为 true
for (int i = 0; i < 4; i++) {
int nextX = dir[i][0] + x;
int nextY = dir[i][1] + y;
if (nextX < 0 || nextX >= grid.length || nextY < 0 || nextY >= grid[0].length) {
continue;
}
if (grid[nextX][nextY] == 1 && !visited[nextX][nextY]) { // 必须是未访问过的陆地,递归终止条件隐含在此
count++; // 先 ++,再进入 dfs
dfs(grid, visited, nextX, nextY);
}
}
}
}
1173

被折叠的 条评论
为什么被折叠?



