題目地址:
https://leetcode.com/problems/shortest-bridge/
給定一個矩陣,含的連通塊視爲一個島嶼,題目保證有兩個島嶼。現在允許將其中的變爲,問至少要改變多少個能使得整個矩陣島嶼數變爲(即將兩個島連通起來)。
思路是雙向BFS。將兩個島嶼分別加入兩個隊列,然後分別一步一步擴張兩個島嶼,直到相交爲止。爲了方便判斷相交,可以事先將其中一個島嶼標記爲,而這個可以用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);
}
}
}
}
時空複雜度。