leetcode 934 最短的桥

leetcode每日一题10/25

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

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

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

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

n <= 100

今天的每日一题,求的是最短路径的最大值。也就是从任意一个1出发,碰见0说明路径长度为1,碰见1说明路径长度为0,然后求单源最短路径的最大值。

或者是并查集求多源Bfs的最小值。当然bfs可以使用双向bfs。

  • 使用01bfs求解单源bfs最小值。
class Solution {
public:
/*

    话说就算知道了知识点,仍旧不好做这道题目啊。
    是有压力了吧。
    如果有了1直接长度为0,如果没有桥长度为1。
    从任意的点出发都可以达到效果。
    或者弄一个超级源点,作为1。
    找这个点到所有点的最短距离就行了。
    最后求单元最短路径的和是多少。
*/
    static const int MAXN = 105;
    int n, m;
    int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int vis[MAXN][MAXN];
    int get(int x, int y) {
        return x * 1001 + y;
    }
    int check(int x, int y) {
        if (x >= n || x < 0 || y >= m || y < 0 || vis[x][y]) 
            return false;
        return true;
    }
    int shortestBridge(vector<vector<int>>& grid) {
        n = grid.size(), m = grid[0].size();
        pair<int, int>PR;
        const int INF = 0x3f3f3f3f;
        vector<int>d(n * 1001 + m + 1, INF);
        deque<int>que;
        for (int i = 0; i < n; i++) {
            int flag = 0;
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1) {
                    que.push_back(get(i, j));
                    d[get(i, j)] = 0;
                    flag = 1;
                    vis[i][j] = 1;
                    break;
                }
            }
            if (flag == 1) break;
        }
        while (!que.empty()) {
            int f = que.front(); que.pop_front();
            int x = f / 1001, y = f % 1001;
            // printf("%d %d\n", x, y);
            int step = d[f];
            for (int i = 0; i < 4; i++) {
                int nx = x + dirs[i][0];
                int ny = y + dirs[i][1];
                if (!check(nx, ny)) continue;
                vis[nx][ny] = 1;
                int id = get(nx, ny);
                if (grid[nx][ny] == 0) {
                    que.push_back(get(nx, ny));
                    d[id] = step + 1;
                }
                else {
                    que.push_front(id);
                    d[id] = step;
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                printf("%d ", d[get(i, j)]);
                if (grid[i][j] == 1) {
                    ans = max(ans, d[get(i, j)]);
                    // printf("%d %d")
                }
            }
            printf("\n");
        }
        return ans;
    }
};
  • 使用并查集 + 双向bfs
class Solution {
    static int N = 10010;
    static int[] p = new int[N];
    static int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
    int n;
    int getIdx(int x, int y) {
        return x * n + y;
    }
    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    void union(int x, int y) {
        p[find(x)] = p[find(y)];
    }
    public int shortestBridge(int[][] g) {
        n = g.length;
        for (int i = 0; i <= n * n; i++) p[i] = i;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 0) continue;
                for (int[] di : dirs) {
                    int x = i + di[0], y = j + di[1];
                    if (x < 0 || x >= n || y < 0 || y >= n) continue;
                    if (g[x][y] == 0) continue;
                    union(getIdx(i, j), getIdx(x, y));
                }
            }
        }
        int a = -1, b = -1;
        Deque<int[]> d1 = new ArrayDeque<>(), d2 = new ArrayDeque<>();
        Map<Integer, Integer> m1 = new HashMap<>(), m2 = new HashMap<>();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (g[i][j] == 0) continue;
                int idx = getIdx(i, j), root = find(idx);
                if (a == -1) a = root;    
                else if (a != root && b == -1) b = root;
                if (root == a) {
                    d1.addLast(new int[]{i, j});
                    m1.put(idx, 0);
                } else if (root == b) {
                    d2.addLast(new int[]{i, j});
                    m2.put(idx, 0);
                }
            }
        }
        while (!d1.isEmpty() && !d2.isEmpty()) {
            int t = -1;
            if (d1.size() < d2.size()) t = update(d1, m1, m2);
            else t = update(d2, m2, m1);
            if (t != -1) return t - 1;
        }
        return -1; // never
    }
    int update(Deque<int[]> d, Map<Integer, Integer> m1, Map<Integer, Integer> m2) {
        int sz = d.size();
        while (sz-- > 0) {
            int[] info = d.pollFirst();
            int x = info[0], y = info[1], idx = getIdx(x, y), step = m1.get(idx);
            for (int[] di : dirs) {
                int nx = x + di[0], ny = y + di[1], nidx = getIdx(nx, ny);
                if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
                if (m1.containsKey(nidx)) continue;
                if (m2.containsKey(nidx)) return step + 1 + m2.get(nidx);
                d.addLast(new int[]{nx, ny});
                m1.put(nidx, step + 1);
            }
        }
        return -1;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值