往期文章 :
题目:
给定一个由 0 和 1 组成的非空二维数组 grid ,用来表示海洋岛屿地图。
一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
找到给定的二维数组中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
示例:
输入: grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出: 6
解释: 对于上面这个给定矩阵应返回 6。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] is either 0 or 1
思路:
DFS深度优先搜索,也可以BFS
遍历所有节点,遇到1就将其进行DFS,统计所有连通块,注意统计count数不能作为函数参数传递,最好使用全局变量,不然会产生统计的值产生回溯。每次取最大值,使用vis数组进行标记,防止重复访问。
class Solution {
public:
vector<vector<bool>> vis;
int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int n, m;
int ret = 0;
int count;
int maxAreaOfIsland(vector<vector<int>>& grid) {
this->n = grid.size();
this->m = grid[0].size();
vis.resize(n, vector<bool>(m, false));
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(grid[i][j] == 1 && vis[i][j] == false) {
vis[i][j] = true;
count = 1;
dfs(i, j, grid);
ret = max(ret, count);
}
}
}
return ret;
}
void dfs(int i, int j, vector<vector<int>>& grid) {
for(int k = 0; k < 4; k++) {
int x = i + dirs[k][0];
int y = j + dirs[k][1];
if(x >= 0 && x < n && y >= 0 && y < m && grid[x][y] == 1 && vis[x][y] == false) {
count++;
vis[x][y] = true;
dfs(x, y, grid);
}
}
}
};
题目:
存在一个 无向图 ,图中有 n 个节点。其中每个节点都有一个介于 0 到 n - 1 之间的唯一编号。
给定一个二维数组 graph ,表示图,其中 graph[u] 是一个节点数组,由节点 u 的邻接节点组成。形式上,对于 graph[u] 中的每个 v ,都存在一条位于节点 u 和节点 v 之间的无向边。该无向图同时具有以下属性:
二分图 定义:如果能将一个图的节点集合分割成两个独立的子集 A 和 B ,并使图中的每一条边的两个节点一个来自 A 集合,一个来自 B 集合,就将这个图称为 二分图 。
如果图是二分图,返回 true ;否则,返回 false 。
输入:graph = [[1,2,3],[0,2],[0,1,3],[0,2]]
输出:false
解释:不能将节点分割成两个独立的子集,以使每条边都连通一个子集中的一个节点与另一个子集中的一个节点。
示例 2:
提示:
graph.length == n
1 <= n <= 100
0 <= graph[u].length < n
0 <= graph[u][i] <= n - 1
graph[u] 不会包含 u
graph[u] 的所有值 互不相同
如果 graph[u] 包含 v,那么 graph[v] 也会包含 u
思路:
BFS广度优先搜索,也可以使用DFS
一个图可能包含多个子图,需要逐次对每个子图涂色。需要一个数组 colors 标记所有节点的颜色,规定 -1 表示当前未涂色,0 表示第一种颜色,1 表示第 2 种颜色。为了给所有的节点着色,需要遍历图内的所有结点,在着色的过程中若碰到已着色,但是不符合一条边两个节点不同颜色的要求,即可判断该图不可能是二分图。
class Solution {
public:
//BFS
bool setColor(vector<vector<int>>& graph, vector<int>& colors, int i, int color) {
colors[i] = color;
queue<int> q;
q.push(i);
while(!q.empty()) {
int top = q.front();
q.pop();
for(auto& gra : graph[top]) {
// 已着色
if(colors[gra] >= 0) {
// 颜色相同
if(colors[gra] == colors[top]) return false;
}else { //未着色
q.push(gra);
colors[gra] = colors[top] == 1? 0 : 1;
}
}
}
return true;
}
bool isBipartite(vector<vector<int>>& graph) {
vector<int> colors(graph.size(), -1);
for(int i = 0; i < graph.size(); i++) {
if(colors[i] == -1) {
if(!setColor(graph, colors, i, 0))
return false;
}
}
return true;
}
};
题目:
给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
示例:
输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
提示:
m == mat.length
n == mat[i].length
1 <= m, n <= 104
1 <= m * n <= 104
mat[i][j] is either 0 or 1.
mat 中至少有一个 0
思路:
BFS广度优先搜索
不能使用DFS深搜,因为DFS必须对于每个 1 计算一次它到所有的 0 的距离,再从中取一个最小值,时间复杂度会非常高。
假设初始只有两个0,使用广搜的执行过程如下
为什么我们这样是正确的呢,因为我们是按队列顺序来逐个计算的,逐渐从0向外扩散,也就是广搜,下面例子进行证明
证明例子:000,010,110
第[2,1]的那个1不会出现距离为2的情况,因为使用的是BFS每次只会扩容四个方向一次,
等所有0遍历一遍才会轮到1
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int n = mat.size(), m = mat[0].size();
vector<vector<int>> dist(n, vector<int>(m, 0));
// 标记是否访问过
vector<vector<bool>> vis(n, vector<bool>(m, false));
queue<pair<int,int>> que;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(mat[i][j] == 0) {
que.push({i,j});
vis[i][j] = true;
}
}
}
while(!que.empty()) {
auto [i,j] = que.front(); que.pop();
for(int k = 0; k < 4; k++) {
int x = i + dirs[k][0];
int y = j + dirs[k][1];
if(x >= 0 && x < n && y >= 0 && y < m && !vis[x][y]) {
vis[x][y] = true;
dist[x][y] = dist[i][j] + 1;
que.push({x,y});
}
}
}
return dist;
}
};