#Leetcode-934. 最短的桥(图算法)

题目:最短的桥

给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。岛是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛 。返回必须翻转的 0 的最小数目。

示例1:

输入:grid = [[0,1],[1,0]]
输出:1

示例2:

输入:grid = [[0,1,0],[0,0,0],[0,0,1]]
输出:2

示例3:

输入:grid = [[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]]
输出:1

思路:

  1. 由于题目给定有且仅存在两个岛屿,因此可以通过遍历的方式找到某个岛屿的一个点;
  2. 通过DFS的方法扩展这个岛屿(通过设置值为2的方式),同时将该点入队列;
  3. 通过BFS方式扩展1岛,设置初始step=1,每轮扩展step++,扩展时候会遇到三种情况:第一遇到的是1岛的点,则不入队,因为该点已经在队中;第二遇到的是水,入队,同时设置该点值为2;第三遇到的是2岛的点,则结束返回此step-1;
class Solution {
public:
    int shortestBridge(vector<vector<int>>& grid) {
        int x, y;
        this->grid = grid;
        int n = grid[0].size();
        queue<point> q;
        findLand(x, y, n);
        DFS(x, y, n, q);
        return BFS(q, n);
    }
    Solution(){
        next_x = {1, -1, 0, 0};
        next_y = {0, 0, 1, -1};
    }
private:
    typedef struct{
        int x, y;
        int step;
    } point;
    vector<vector<int>> grid;
    vector<int> next_x;
    vector<int> next_y;
    void findLand(int &x , int &y, int n){
        for(x = 0; x < n; x ++){
            for(y = 0; y < n; y++){
                if(grid[x][y] == 1){
                    return;
                }
            }
        }
    }
    void DFS(int x, int y, int n, queue<point> &q){
        grid[x][y] = 2;
        point p = {x, y, 0};
        q.push(p);
        for(int i = 0; i < 4; i++){
            x += next_x[i];
            y += next_y[i];
            if(judge(x, y, n) && grid[x][y] == 1){
                DFS(x,y,n, q);
            }
            x -= next_x[i];
            y -= next_y[i];
        }
    }
    int BFS(queue<point> &q, int n){
        int cur_x, cur_y, cur_step;
        while(!q.empty()){
            point cur = q.front();
            q.pop();
            for(int i = 0; i < 4; i++){
                cur_x = cur.x + next_x[i];
                cur_y = cur.y + next_y[i];
                cur_step = cur.step + 1;
                if(!judge(cur_x, cur_y, n) || grid[cur_x][cur_y] == 2){
                    continue;
                }
                if(grid[cur_x][cur_y] == 1){
                    return cur_step-1;
                }
                grid[cur_x][cur_y] = 2;
                point next = {cur_x, cur_y, cur_step};
                q.push(next);
            }
        }
        return 0;
    }
    bool judge(int x, int y, int n){
        if(x < 0 || x >= n || y < 0 || y >= n){
            return false;
        }
        return true;
    }
};

来源LeetCode

一些其他知识

在写题过程中,我希望能够定义两个常量数组: const int next_x[4], next_y[4] 方便后续岛屿扩展。但我发现我无法完成这样一个操作。

通过检索我发现了有关回答和建议:How initialize const array class member

// You cannot explicitly initialize a non-static const array
// in a class.
// But if the array is const why not make it static? 
// I can't think of any obvious reason why not.
// If you really needed this for some reason then 
// I would do something like this
struct A
{
A() { i[0] = 1; i[1] = 2; i[2] = 3]; }
int i[3];
};

class C {
private:
const A a;
public:
C();
};

其实仔细想想,我想实现的并非是const int next_x[4], 而是static const int next x[4],因为对于一个常量数组对于每一个对象而言都是一样的,那么我们完全没必要为每一个对象都创建单独的一份,因此将他与其他静态变量存储在一起,而不是存储在对象中。
因此可以改为:

class Solution {
public:
    static const int next_x[4] = {1, -1, 0, 0};
    static const int next_y[4] = {0, 0, 1, -1};
    void shortestBridge() {
        for(int i = 0; i < 4; i++){
            cout<<next_x[i]<<" "<<next_y[i]<<endl;
        }
    }
    Solution(){
    }
};

然而报错:error: ‘constexpr’ needed for in-class initialization of static data member ‘const int Solution::next_x [4]’ of non-integral type [-fpermissive]|
提示要加入关键字constexpr,对于这个关键字曾在书中看过但没深入了解。因此修改为:

class Solution {
public:
    constexpr static const int next_x[4] = {1, -1, 0, 0};
    constexpr static const int next_y[4] = {0, 0, 1, -1};
    void shortestBridge() {
        for(int i = 0; i < 4; i++){
            cout<<next_x[i]<<" "<<next_y[i]<<endl;
        }
    }
    Solution(){
    }
};

结果报错:
undefined reference to Solution::next_y,
undefined reference to Solution::next_x

后面发现答案是:在C++17 (如C++11和C++14)之前,类内的C++静态常量数组初始化您必须添加下面内容。解答来源的链接
constexpr int Soluton::next_x[3][2];
constexpr int Soluton::next_y[3][2];

class Solution {
public:
    constexpr static const int next_x[4] = {1, -1, 0, 0};
    constexpr static const int next_y[4] = {0, 0, 1, -1};
    void showNum(){
        for(int i = 0; i < 4; i++){
            cout<<next_x[i]<<" "<<next_y[i]<<endl;
        }
    }
};
constexpr int Solution::next_x[4];
constexpr int Solution::next_y[4];

此外,C++静态常量在类外初始化也可以正常编译

class Solution{
private:
	static const int next_x[4];
	static const int next_y[4];
};
const int Solution::next_x[4] = {1, -1, 0, 0};
const int Solution::next_y[4] = {0, 0, 1, -1};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值