934. Shortest Bridge

题目传送门

题目分析

这个题目其实可以简化为三个步骤
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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值