题目分析
这个题目其实可以简化为三个步骤
1、找到第一个岛的边
2、从第一个岛的边开始进行广度优先遍历
3、广度优先遍历到出现第二关岛时停止。
为实现这个算法,我们需要解决如下问题:
如何找到小岛的边、如何区分我们出发的岛和我们要找到的岛
源代码
代码写得太丑,凑活看吧。
class Solution{
public:
void genBorder(vector<vector<int>>& A, queue<pair<int, int>> &border, int x, int y){
queue<pair<int, int>> q;
q.push({x, y});
while(!q.empty()){
auto coord = q.front();
q.pop();
int x{coord.first}, y{coord.second};
// 4 ordinate
A[x][y] = 2;
if(x > 0 && A[x - 1][y] == 1){
A[x - 1][y] = 2;
q.push({x-1, y});
}
if(y > 0 && A[x][y - 1] == 1){
A[x][y - 1] = 2;
q.push({x, y - 1});
}
if(x < A[0].size() - 1 && A[x + 1][y] == 1){
A[x + 1][y] = 2;
q.push({x + 1, y});
}
if(y < A.size() - 1 && A[x][y + 1] == 1){
A[x][y + 1] = 2;
q.push({x, y + 1});
}
// judge is border
if( (x > 0 && A[x - 1][y] == 0) ||
(y > 0 && A[x][y - 1] == 0) ||
(x < A[0].size() - 1 && A[x + 1][y] == 0) ||
(y < A.size() - 1 && A[x][y + 1] == 0))
border.push({x, y});
}
}
int shortestBridge(vector<vector<int>>& A) {
bool found = false;
int mm = 0;
queue<pair<int, int>> border;
for(int i = 0; i < A.size() && !found; i++){
for(int j = 0; j < A[i].size() && !found; j++){
if(A[i][j] == 1){
genBorder(A, border, i, j);
found = true;
}
}
}
found = false;
while(!border.empty() && !found){
int borsize = border.size();
mm++;
for(int i = 0; i < borsize && !found; i++){
auto coord = border.front();
border.pop();
int x{coord.first}, y{coord.second};
// 4 ordinate
if(x > 0 && A[x - 1][y] == 0){
A[x - 1][y] = 2;
border.push({x-1, y});
}
if(y > 0 && A[x][y - 1] == 0){
A[x][y - 1] = 2;
border.push({x, y - 1});
}
if(x < A[0].size() - 1 && A[x + 1][y] == 0){
A[x + 1][y] = 2;
border.push({x + 1, y});
}
if(y < A.size() - 1 && A[x][y + 1] == 0){
A[x][y + 1] = 2;
border.push({x, y + 1});
}
if( (x > 0 && A[x - 1][y] == 1) ||
(y > 0 && A[x][y - 1] == 1) ||
(x < A[0].size() - 1 && A[x + 1][y] == 1) ||
(y < A.size() - 1 && A[x][y + 1] == 1))
found = true;
}
}
return mm - 1;
}
};
这里我给出第二种方法,但是这个方法对这个问题没有多好的效果。不过时间复杂度一致,差别在与使用了额外的存储空间。
我们可以不假思索地证明,在二维空间下,从一个小岛至另一个小岛的最短距离,至多进行一次偏转。即这个最短距离要么是一条直线,要么是一个90度的折现,不会出现偏折两次的情况。
那么我们只用计算出一个0
到其中一个小岛的最短距离,并存储下来。其中这个距离是水平距离或者是垂直距离。
我们构造两个这样的距离矩阵landA[][], landB[][]
。
然后我们只要遍历每个0
点,求min(landA[][] + landB[][])
即可
class Solution {
public:
void isLandNote(vector<vector<int>>& A, int x, int y){
queue<pair<int, int>> q;
q.push({x, y});
while(!q.empty()){
auto coord = q.front();
q.pop();
int x{coord.first}, y{coord.second};
A[x][y] = 2;
// 4 ordinate
if(x > 0 && A[x - 1][y] == 1){
A[x - 1][y] = 2;
q.push({x-1, y});
}
if(y > 0 && A[x][y - 1] == 1){
A[x][y - 1] = 2;
q.push({x, y - 1});
}
if(x < A[0].size() - 1 && A[x + 1][y] == 1){
A[x + 1][y] = 2;
q.push({x + 1, y});
}
if(y < A.size() - 1 && A[x][y + 1] == 1){
A[x][y + 1] = 2;
q.push({x, y + 1});
}
}
}
void direShort(vector<vector<int>>& A, vector<vector<int>>& landA, int note){
vector<vector<int>> row(A.size(), vector<int>(A[0].size(), 0));
vector<vector<int>> col(A.size(), vector<int>(A[0].size(), 0));
// row
for(int i = 0;i < A.size(); i++){
// left to right
int base = -1;
for(int j = 0; j < A[i].size(); j++){
if(A[i][j] == note)
base = 0;
else{
if(base >= 0)
base++;
row[i][j] = base;
}
}
// right to left
base = -1;
for(int j = A[i].size() - 1; j >= 0; j--){
if(A[i][j] == note)
base = 0;
else{
if(base >= 0)
base++;
row[i][j] = (base == -1 || row[i][j] == -1 ? max(base, row[i][j]) : min(base, row[i][j]));
}
}
}
// col
for(int i = 0;i < A[0].size(); i++){
// left to right
int base = -1;
for(int j = 0; j < A.size(); j++){
if(A[j][i] == note)
base = 0;
else{
if(base >= 0)
base++;
col[j][i] = base;
}
}
// right to left
base = -1;
for(int j = A.size() - 1; j >= 0; j--){
if(A[j][i] == note)
base = 0;
else{
if(base >= 0)
base++;
col[j][i] = (base == -1 || col[j][i] == -1 ? max(base, col[j][i]) : min(base, col[j][i]));
}
}
}
for(int i = 0; i < A.size(); i++){
for(int j = 0; j < A[i].size(); j++)
landA[i][j] = row[i][j] == -1 || col[i][j] == -1? max(row[i][j], col[i][j]) : min(row[i][j], col[i][j]);
}
return;
}
int shortestBridge(vector<vector<int>>& A) {
bool found = false;
int mm = INT32_MAX;
vector<vector<int>> landA(A.size(), vector<int>(A[0].size(), 0));
vector<vector<int>> landB(A.size(), vector<int>(A[0].size(), 0));
for(int i = 0; i < A.size() && !found; i++){
for(int j = 0; j < A[i].size() && !found; j++){
if(A[i][j] == 1){
isLandNote(A, i, j);
found = true;
}
}
}
direShort(A, landA, 1);
direShort(A, landB, 2);
for(int i = 0; i < A.size(); i++){
for(int j = 0; j < A[i].size(); j++){
if(A[i][j] == 0){
if(landA[i][j] == -1 || landB[i][j] == -1)
continue;
mm = min(mm, landA[i][j] + landB[i][j]);
}
}
}
return mm - 1;
}
};