題目地址:
https://www.lintcode.com/problem/shortest-bridge/description
給定一個二維矩陣,含的連通塊形成一個島嶼。題目保證矩陣中有兩個島嶼,允許將其中的變爲,問至少改變多少個能使得兩個島嶼連通。
思路是雙向BFS。首先需要將兩個島嶼區分開來,所以先遍歷矩陣,將其中一個含的連通塊標記爲,這一步可以用DFS來做。接着將標記爲的島嶼和標記爲的島嶼分別進兩個隊列做雙向BFS,每次擴展一步邊界,即將邊界向外走一格的改變爲島嶼的編號或者,直到走到交界處爲止,返回走的步數即可。代碼如下:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Solution {
public int ShortestBridge(int[][] A) {
Queue<int[]> beginQueue = new LinkedList<>(), endQueue = new LinkedList<>();
// marked記錄有沒有找到島嶼
boolean marked = false;
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < A[0].length; j++) {
// 一旦找到了島嶼,就將其標記爲2,然後記marked爲true
if (A[i][j] == 1) {
dfs(i, j, A);
marked = true;
break;
}
}
// 如果標記過其中一個島嶼了,就退出循環
if (marked) {
break;
}
}
// 將標記爲1和標記爲2的兩個島嶼分別加進兩個隊列
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});
} else 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則返回步數,否則標記爲1並加入隊列
for (int[] next : getNexts(cur[0], cur[1], A, 1)) {
if (A[next[0]][next[1]] == 2) {
return res;
}
A[next[0]][next[1]] = 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)) {
if (A[next[0]][next[1]] == 1) {
return res;
}
A[next[0]][next[1]] = 2;
endQueue.offer(next);
}
}
res++;
}
// 這個問題的解一定是存在的,所以這一步事實上是走不到的
return 0;
}
// 返回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 (inBound(nextX, nextY, A) && 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 (inBound(nextX, nextY, A) && A[nextX][nextY] == 1) {
dfs(nextX, nextY, A);
}
}
}
private boolean inBound(int x, int y, int[][] A) {
return 0 <= x && x < A.length && 0 <= y && y < A[0].length;
}
}
時空複雜度。