934. 最短的桥(难度:中等)

题目链接:https://leetcode.cn/problems/shortest-bridge/

题目描述:

给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。

是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid恰好存在两座岛

你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛

返回必须翻转的 0 的最小数目。

示例 1:

输入:grid = [[0,1],[1,0]]
输出:1

示例 2:

输入:grid = [[0,1,0],[0,0,0],[0,0,1]]
输出:2

示例 3:

输入:grid = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:1

提示:

  • n == grid.length == grid[i].length
  • 2 <= n <= 100
  • grid[i][j]01
  • grid 中恰有两个岛

解法:深度优先遍历+广度优先遍历

创建一个队列deque用于存放岛屿边缘坐标。

先遍历二元矩阵,找到任意一块陆地,分别向上下左右四个方向开始深度优先遍历,当遇到陆地时,代表是同一块岛屿,将其标记为2,当遇到水域时,表示到了岛屿边缘,将其也标记为2,并添加到一个队列中。

这样遍历一次,就得到了第一块岛屿的所有边缘坐标。

然后在通过对这边边缘坐标广度优先遍历,让其向外扩张,每次扩张一步,当遇到水域,就将其标记为2,添加到deque中,直到遇到陆地,表示两岛相连,返回扩张次数。

代码:

class Solution {
    Deque<int[]> deque = new ArrayDeque<>();
    int[][] dp = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    int[][] grid;
    boolean[][] isFlag;
    int result = 0;

    public int shortestBridge(int[][] grid) {
        this.grid = grid;
        boolean flag = false;
        this.isFlag = new boolean[grid.length][grid[0].length];
        for (int i = 0; i < grid.length && !flag; i++) {
            for (int j = 0; j < grid[0].length && !flag; j++) {
                if (grid[i][j] == 1) {
                    flag = true;
                    calc(i, j);
                }
            }
        }

        while (!deque.isEmpty()) {
            result++;
            int len = deque.size();
            for (int i = 0; i < len; i++) {
                int[] temp = deque.pollFirst();
                for (int[] ints : dp) {
                    int nex = temp[0] + ints[0], ney = temp[1] + ints[1];
                    if (isLegal(nex, ney) && grid[nex][ney] == 0) {
                        deque.addLast(new int[]{nex, ney});
                        grid[nex][ney] = 2;
                    } else if (isLegal(nex, ney) && grid[nex][ney] == 1) {
                        return result;
                    }
                }
            }
        }
        return result;
    }

    public void calc(int row, int col) {
        if (!isLegal(row, col) || grid[row][col] == 2) return;
        if (grid[row][col] == 0) {
            grid[row][col] = 2; // 将边界向外扩展1层岛屿(val=2)
            deque.addLast(new int[]{row, col});
            return;
        }
        grid[row][col] = 2; // 为岛屿打标记(val=2)
        for (int[] c : dp) calc(row + c[0], col + c[1]); // 深度遍历某个格子的四个方向
    }

    public boolean isLegal(int row, int column) {
        return row >= 0 && row < grid.length && column >= 0 && column < grid[0].length;
    }

}   
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容