题目:最短的桥
给你一个大小为 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
思路:
- 由于题目给定有且仅存在两个岛屿,因此可以通过遍历的方式找到某个岛屿的一个点;
- 通过DFS的方法扩展这个岛屿(通过设置值为2的方式),同时将该点入队列;
- 通过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;
}
};
一些其他知识
在写题过程中,我希望能够定义两个常量数组: 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};