搜索题目:使陆地分离的最少天数

文章目录

题目

标题和出处

标题:使陆地分离的最少天数

出处:1568. 使陆地分离的最少天数

难度

8 级

题目描述

要求

给定一个 m × n \texttt{m} \times \texttt{n} m×n 的二进制网格 grid \texttt{grid} grid,其中 1 \texttt{1} 1 代表陆地, 0 \texttt{0} 0 代表水域。岛屿是由相邻的 1 \texttt{1} 1 在水平方向或竖直方向上连接构成的最大组合。

如果恰好有一个岛屿 ,则认为网格是连通 的,否则网格是分离的。

一天内,可以将任何单个陆地单元( 1 \texttt{1} 1)更改为水单元( 0 \texttt{0} 0)。

返回使陆地分离的最少天数。

示例

示例 1:

输入: grid = \[0,1,1,0,0,1,1,0,0,0,0,0] \texttt{grid = \[0,1,1,0,0,1,1,0,0,0,0,0]} grid = \[0,1,1,0,0,1,1,0,0,0,0,0]

输出: 2 \texttt{2} 2

解释:至少需要 2 \texttt{2} 2 天得到分离的陆地。

将陆地 grid11 \texttt{grid11} grid11 和 grid02 \texttt{grid02} grid02 更改为水,得到两个分离的岛屿。

示例 2:

输入: grid = \[1,1] \texttt{grid = \[1,1]} grid = \[1,1]

输出: 2 \texttt{2} 2

解释:如果网格中都是水,也是分离的( \[1,1] → \[0,0] \texttt{\[1,1]} \rightarrow \texttt{\[0,0]} \[1,1]→\[0,0])。零岛屿。

数据范围

  • m = grid.length \texttt{m} = \texttt{grid.length} m=grid.length
  • n = gridi.length \texttt{n} = \texttt{gridi.length} n=gridi.length
  • 1 ≤ m, n ≤ 30 \texttt{1} \le \texttt{m, n} \le \texttt{30} 1≤m, n≤30
  • gridij \texttt{gridij} gridij 为 0 \texttt{0} 0 或 1 \texttt{1} 1

前言

如果初始时网格中没有岛屿或者有至少两个岛屿,则陆地已经分离,不需要将任何陆地单元更改为水单元,最少天数是 0 0 0。

如果初始时网格中有一个或两个陆地单元组成的岛屿,则需要将所有陆地单元更改为水单元,最少天数等于陆地单元的数目。

如果初始时网格中恰好有一个岛屿,则岛屿一定存在角落,岛屿角落的单元最多和两个陆地单元相连,将与岛屿角落相连的陆地单元更改为水单元之后,岛屿角落的单元成为独立的岛屿,此时陆地分离。因此使陆地分离的最少天数不超过 2 2 2。如果将 1 1 1 个陆地单元更改为水单元可以使陆地分离,则最少天数是 1 1 1,否则最少天数是 2 2 2。

因此,最少天数一定不超过 2 2 2。问题转化成判断是否可以通过将 1 1 1 个陆地单元更改为水单元可以使陆地分离。

根据上述分析,计算使陆地分离的最少天数的做法如下。

  1. 计算初始时网格中的岛屿数量,如果初始岛屿数量不等于 1 1 1,则最少天数是 0 0 0。

  2. 如果初始岛屿数量等于 1 1 1,则遍历每个陆地单元,分别计算将每个陆地单元更改为水单元之后的岛屿数量。如果存在一个陆地单元,将该陆地单元更改为水单元之后的岛屿数量不等于 1 1 1,则最少天数是 1 1 1。如果不存在这样的陆地单元,则最少天数是 2 2 2。

计算岛屿数量可以使用广度优先搜索或深度优先搜索实现。

解法一

思路和算法

使用广度优先搜索计算岛屿数量的做法是,依次遍历网格中的每个单元,如果遇到一个单元是陆地且状态是未访问,则遇到一个新的岛屿,将岛屿数量加 1 1 1,并使用广度优先搜索访问与当前陆地连接的所有陆地,即访问当前岛屿的所有单元。遍历结束之后,即可得到岛屿数量。

如果初始岛屿数量等于 1 1 1,则依次遍历每个陆地,对于每个陆地,将陆地更改为水之后计算岛屿数量,计算结束之后将该单元恢复成陆地,继续遍历其他的陆地。

代码

java 复制代码
class Solution {
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int m, n;
    int[][] grid;

    public int minDays(int[][] grid) {
        this.m = grid.length;
        this.n = grid[0].length;
        this.grid = grid;
        if (numIslands() != 1) {
            return 0;
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    grid[i][j] = 0;
                    if (numIslands() != 1) {
                        return 1;
                    }
                    grid[i][j] = 1;
                }
            }
        }
        return 2;
    }

    public int numIslands() {
        int islands = 0;
        boolean[][] visited = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0 || visited[i][j]) {
                    continue;
                }
                islands++;
                visited[i][j] = true;
                Queue<int[]> queue = new ArrayDeque<int[]>();
                queue.offer(new int[]{i, j});
                while (!queue.isEmpty()) {
                    int[] cell = queue.poll();
                    int row = cell[0], col = cell[1];
                    for (int[] dir : dirs) {
                        int newRow = row + dir[0], newCol = col + dir[1];
                        if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && grid[newRow][newCol] == 1 && !visited[newRow][newCol]) {
                            visited[newRow][newCol] = true;
                            queue.offer(new int[]{newRow, newCol});
                        }
                    }
                }
            }
        }
        return islands;
    }
}

复杂度分析

  • 时间复杂度: O ( m 2 n 2 ) O(m^2n^2) O(m2n2),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。计算初始岛屿数量需要 O ( m n ) O(mn) O(mn) 的时间,对于每个陆地单元更改为水单元之后计算岛屿数量需要 O ( m n ) O(mn) O(mn) 的时间,由于陆地单元的数量是 O ( m n ) O(mn) O(mn),因此对于所有陆地单元计算更改为水单元之后的岛屿数量需要 O ( m 2 n 2 ) O(m^2n^2) O(m2n2) 的时间,总时间复杂度是 O ( m n + m 2 n 2 ) = O ( m 2 n 2 ) O(mn + m^2n^2) = O(m^2n^2) O(mn+m2n2)=O(m2n2)。

  • 空间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。记录每个单元格是否访问过的二维数组和队列需要 O ( m n ) O(mn) O(mn) 的空间。

解法二

思路和算法

使用深度优先搜索计算岛屿数量的做法是,依次遍历网格中的每个单元,如果遇到一个单元是陆地且状态是未访问,则遇到一个新的岛屿,将岛屿数量加 1 1 1,并使用深度优先搜索访问与当前陆地连接的所有陆地,即访问当前岛屿的所有单元。遍历结束之后,即可得到岛屿数量。

如果初始岛屿数量等于 1 1 1,则依次遍历每个陆地,对于每个陆地,将陆地更改为水之后计算岛屿数量,计算结束之后将该单元恢复成陆地,继续遍历其他的陆地。

代码

java 复制代码
class Solution {
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int m, n;
    int[][] grid;
    boolean[][] visited;

    public int minDays(int[][] grid) {
        this.m = grid.length;
        this.n = grid[0].length;
        this.grid = grid;
        if (numIslands() != 1) {
            return 0;
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    grid[i][j] = 0;
                    if (numIslands() != 1) {
                        return 1;
                    }
                    grid[i][j] = 1;
                }
            }
        }
        return 2;
    }

    public int numIslands() {
        int islands = 0;
        this.visited = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0 || visited[i][j]) {
                    continue;
                }
                islands++;
                dfs(i, j);
            }
        }
        return islands;
    }

    public void dfs(int row, int col) {
        visited[row][col] = true;
        for (int[] dir : dirs) {
            int newRow = row + dir[0], newCol = col + dir[1];
            if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && grid[newRow][newCol] == 1 && !visited[newRow][newCol]) {
                dfs(newRow, newCol);
            }
        }
    }
}

复杂度分析

  • 时间复杂度: O ( m 2 n 2 ) O(m^2n^2) O(m2n2),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。计算初始岛屿数量需要 O ( m n ) O(mn) O(mn) 的时间,对于每个陆地单元更改为水单元之后计算岛屿数量需要 O ( m n ) O(mn) O(mn) 的时间,由于陆地单元的数量是 O ( m n ) O(mn) O(mn),因此对于所有陆地单元计算更改为水单元之后的岛屿数量需要 O ( m 2 n 2 ) O(m^2n^2) O(m2n2) 的时间,总时间复杂度是 O ( m n + m 2 n 2 ) = O ( m 2 n 2 ) O(mn + m^2n^2) = O(m^2n^2) O(mn+m2n2)=O(m2n2)。

  • 空间复杂度: O ( m n ) O(mn) O(mn),其中 m m m 和 n n n 分别是网格 grid \textit{grid} grid 的行数和列数。记录每个单元格是否访问过的二维数组和递归调用栈需要 O ( m n ) O(mn) O(mn) 的空间。

相关推荐
伟大的车尔尼5 天前
搜索题目:获取所有钥匙的最短路径
广度优先搜索
伟大的车尔尼8 天前
太平洋大西洋漂流记阅读理解
深度优先搜索·广度优先搜索·太平洋·大西洋·阅读理解
伟大的车尔尼11 天前
搜索题目:隔离病毒
深度优先搜索·广度优先搜索
伟大的车尔尼18 天前
搜索题目:穿过迷宫的最少移动次数
广度优先搜索
汉克老师21 天前
GESP6级C++考试语法知识(二十七、广度优先搜索(二、二维BFS))
c++·算法·图论·宽度优先·广度优先搜索·gesp6级·gesp六级
伟大的车尔尼24 天前
搜索题目:为高尔夫比赛砍树
广度优先搜索
伟大的车尔尼25 天前
搜索题目:滑动谜题
广度优先搜索
伟大的车尔尼1 个月前
搜索题目:颜色交替的最短路径
广度优先搜索
伟大的车尔尼1 个月前
搜索题目:验证二叉树
并查集·深度优先搜索·广度优先搜索