In a given 2D binary array `A`, there are two islands. (An island is a 4-directionally connected group of `1`s not connected to any other 1s.)
Now, we may change 0s to 1s so as to connect the two islands together to form 1 island.
Return the smallest number of 0s that must be flipped. (It is guaranteed that the answer is at least 1.)
Example 1:
Input: [[0,1],[1,0]]
Output: 1
Example 2:
Input: [[0,1,0],[0,0,0],[0,0,1]]
Output: 2
Example 3:
Input: [[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]]
Output: 1
Note:
1 <= A.length = A[0].length <= 100A[i][j] == 0orA[i][j] == 1
這道題說是有一個只有0和1的二維數組,其中連在一起的1表示島嶼,現在假定給定的數組中一定有兩個島嶼,問最少需要把多少個0變成1才能使得兩個島嶼相連。在 LeetCode 中關於島嶼的題目還不少,但是萬變不離其宗,核心都是用 DFS 或者 BFS 來解,有些還可以用聯合查找 Union Find 來做。這里要求的是最小值,首先預定了一個 BFS,這就相當於洪水擴散一樣,一圈一圈的,用的就是 BFS 的層序遍歷。好,現在確定了這點后,再來想,這里並不是從某個點開始擴散,而是要從一個島嶼開始擴散,那么這個島嶼的所有的點都是 BFS 的起點,都是要放入到 queue 中的,所以要先來找出一個島嶼的所有點。找的方法就是遍歷數組,找到第一個1的位置,然后對其調用 DFS 或者 BFS 來找出所有相連的1,先來用 DFS 的方法,對第一個為1的點調用遞歸函數,將所有相連的1都放入到一個隊列 queue 中,並且將該點的值改為2,然后使用 BFS 進行層序遍歷,每遍歷一層,結果 res 都增加1,當遇到1時,直接返回 res 即可,參見代碼如下:
解法一:
class Solution {
public:
int shortestBridge(vector<vector<int>>& A) {
int res = 0, n = A.size(), startX = -1, startY = -1;
queue<int> q;
vector<int> dirX{-1, 0, 1, 0}, dirY = {0, 1, 0, -1};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (A[i][j] == 0) continue;
startX = i; startY = j;
break;
}
if (startX != -1) break;
}
helper(A, startX, startY, q);
while (!q.empty()) {
for (int i = q.size(); i > 0; --i) {
int t = q.front(); q.pop();
for (int k = 0; k < 4; ++k) {
int x = t / n + dirX[k], y = t % n + dirY[k];
if (x < 0 || x >= n || y < 0 || y >= n || A[x][y] == 2) continue;
if (A[x][y] == 1) return res;
A[x][y] = 2;
q.push(x * n + y);
}
}
++res;
}
return res;
}
void helper(vector<vector<int>>& A, int x, int y, queue<int>& q) {
int n = A.size();
if (x < 0 || x >= n || y < 0 || y >= n || A[x][y] == 0 || A[x][y] == 2) return;
A[x][y] = 2;
q.push(x * n + y);
helper(A, x + 1, y, q);
helper(A, x, y + 1, q);
helper(A, x - 1, y, q);
helper(A, x, y - 1, q);
}
};
我們也可以使用 BFS 來找出所有相鄰的1,再加上后面的層序遍歷的 BFS,總共需要兩個 BFS,注意這里第一個 BFS 不需要是層序遍歷的,而第二個 BFS 是必須層序遍歷,可以對比一下看一下這兩種寫法有何不同,參見代碼如下:
解法二:
class Solution {
public:
int shortestBridge(vector<vector<int>>& A) {
int res = 0, n = A.size();
queue<int> q, que;
vector<int> dirX{-1, 0, 1, 0}, dirY = {0, 1, 0, -1};
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (A[i][j] == 0) continue;
A[i][j] = 2;
que.push(i * n + j);
break;
}
if (!que.empty()) break;
}
while (!que.empty()) {
int t = que.front(); que.pop();
q.push(t);
for (int k = 0; k < 4; ++k) {
int x = t / n + dirX[k], y = t % n + dirY[k];
if (x < 0 || x >= n || y < 0 || y >= n || A[x][y] == 0 || A[x][y] == 2) continue;
A[x][y] = 2;
que.push(x * n + y);
}
}
while (!q.empty()) {
for (int i = q.size(); i > 0; --i) {
int t = q.front(); q.pop();
for (int k = 0; k < 4; ++k) {
int x = t / n + dirX[k], y = t % n + dirY[k];
if (x < 0 || x >= n || y < 0 || y >= n || A[x][y] == 2) continue;
if (A[x][y] == 1) return res;
A[x][y] = 2;
q.push(x * n + y);
}
}
++res;
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/934
類似題目:
參考資料:
https://leetcode.com/problems/shortest-bridge/
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)
