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;
    }

}	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值