【Leetcode】934. Shortest Bridge

題目地址:

https://leetcode.com/problems/shortest-bridge/

給定一個010-1矩陣,含11的連通塊視爲一個島嶼,題目保證有兩個島嶼。現在允許將其中的00變爲11,問至少要改變多少個00能使得整個矩陣島嶼數變爲11(即將兩個島連通起來)。

思路是雙向BFS。將兩個島嶼分別加入兩個隊列,然後分別一步一步擴張兩個島嶼,直到相交爲止。爲了方便判斷相交,可以事先將其中一個島嶼標記爲22,而這個可以用DFS來做。這樣就能區分出兩個島嶼了。代碼如下:

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

public class Solution {
    public int shortestBridge(int[][] A) {
        if (A == null || A.length == 0 || A[0].length == 0) {
            return 0;
        }
    
    	// 將其中一個島嶼標記爲2,標記完後就退出
        boolean marked = false;
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j < A[0].length; j++) {
                if (A[i][j] == 1) {
                    dfs(i, j, A);
                    marked = true;
                    break;
                }
            }
            if (marked) {
                break;
            }
        }
        
        // 分別將兩個島嶼加入兩個隊列
        Queue<int[]> beginQueue = new ArrayDeque<>(), endQueue = new ArrayDeque<>();
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j < A[0].length; j++) {
                if (A[i][j] == 1) {
                    beginQueue.offer(new int[]{i, j});
                }
                if (A[i][j] == 2) {
                    endQueue.offer(new int[]{i ,j});
                }
            }
        }
        
        int res = 0;
        while (!beginQueue.isEmpty() && !endQueue.isEmpty()) {
            int beginSize = beginQueue.size(), endSize = endQueue.size();
            for (int i = 0; i < beginSize; i++) {
                int[] cur = beginQueue.poll();
                // 得到cur四個方向上不等於1的座標,如果發現了2則返回步數,
                // 如果是0則將其變爲1(相當於向外擴張一步)
                for (int[] next : getNexts(cur[0], cur[1], A, 1)) {
                    int nextX = next[0], nextY = next[1];
                    if (A[nextX][nextY] == 2) {
                        return res;
                    }
                    A[nextX][nextY] = 1;
                    beginQueue.offer(next);
                }
            }
            
            res++;
            for (int i = 0; i < endSize; i++) {
                int[] cur = endQueue.poll();
                for (int[] next : getNexts(cur[0], cur[1], A, 2)) {
                    int nextX = next[0], nextY = next[1];
                    if (A[nextX][nextY] == 1) {
                        return res;
                    }
                    A[nextX][nextY] = 2;
                    endQueue.offer(next);
                }
            }
            res++;
        }
        
        return -1;
    }
    
    // 把A[x][y]四個方向相鄰的且不等於mark的座標返回
    private List<int[]> getNexts(int x, int y, int[][] A, int mark) {
        List<int[]> nexts = new ArrayList<>();
        int[] d = {0, 1, 0, -1, 0};
        for (int i = 0; i < 4; i++) {
            int nextX = x + d[i], nextY = y + d[i + 1];
            if (0 <= nextX && nextX < A.length && 0 <= nextY && nextY < A[0].length && A[nextX][nextY] != mark) {
                nexts.add(new int[]{nextX, nextY});
            }
        }
        
        return nexts;
    }
    
    private void dfs(int x, int y, int[][] A) {
        A[x][y] = 2;
        int[] d = {0, 1, 0, -1, 0};
        for (int i = 0; i < 4; i++) {
            int nextX = x + d[i], nextY = y + d[i + 1];
            if (0 <= nextX && nextX < A.length && 0 <= nextY && nextY < A[0].length && A[nextX][nextY] == 1) {
                dfs(nextX, nextY, A);
            }
        }
    }
}

時空複雜度O(mn)O(mn)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章