持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
广度优先搜索
1765. 地图中的最高点
题目 给你一个大小为 m x n 的整数矩阵 isWater ,它代表了一个由 陆地 和 水域 单元格组成的地图。
如果 isWater[i][j] == 0 ,格子 (i, j) 是一个 陆地 格子。
如果 isWater[i][j] == 1 ,格子 (i, j) 是一个 水域 格子。
你需要按照如下规则给每个单元格安排高度:
每个格子的高度都必须是非负的。 如果一个格子是是 水域 ,那么它的高度必须为 0 。 任意相邻的格子高度差 至多 为 1 。当两个格子在正东、南、西、北方向上相互紧挨着,就称它们为相邻的格子。(也就是说它们有一条公共边) 找到一种安排高度的方案,使得矩阵中的最高高度值 最大 。
请你返回一个大小为 m x n 的整数矩阵 height ,其中 height[i][j] 是格子 (i, j) 的高度。如果有多种解法,请返回 任意一个 。
示例 1:
输入:isWater = [[0,1],[0,0]]
输出:[[1,0],[2,1]]
解释:上图展示了给各个格子安排的高度。
蓝色格子是水域格,绿色格子是陆地格。
示例 2:
输入:isWater = [[0,0,1],[1,0,0],[0,0,0]]
输出:[[1,1,0],[0,1,1],[1,2,2]]
解释:所有安排方案中,最高可行高度为 2 。
任意安排方案中,只要最高高度为 2 且符合上述规则的,都为可行方案。
代码
提示:
m == isWater.length
n == isWater[i].length
1 <= m, n <= 1000
isWater[i][j] 要么是 0 ,要么是 1 。
至少有 1 个水域格子。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ma… 代码
class Solution {
public:
int mx[4] = {0, 0, 1, -1};
int my[4] = {1, -1, 0, 0};
vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {
int m=isWater.size(), n=isWater[0].size();
vector<vector<int>> v(m, vector<int>(n, -1));
queue<pair<int, int>> q;
for(int i=0; i < m; i++){
for(int j=0; j < n; j++){
if(isWater[i][j]){
q.emplace(i, j);
v[i][j] = 0;
}
}
}
while(!q.empty()){
auto &p = q.front();
for(int i=0; i < 4; i++){
int x = p.first+mx[i], y = p.second+my[i];
if(x >= 0 && x < m && y >= 0 && y < n && v[x][y] == -1){
q.emplace(x, y);
v[x][y] = v[p.first][p.second]+1;
}
}
q.pop();
}
return v;
}
};
2045. 到达目的地的第二短时间
题目 城市用一个 双向连通 图表示,图中有 n 个节点,从 1 到 n 编号(包含 1 和 n)。图中的边用一个二维整数数组 edges 表示,其中每个 edges[i] = [ui, vi] 表示一条节点 ui 和节点 vi 之间的双向连通边。每组节点对由 最多一条 边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time 分钟。
每个节点都有一个交通信号灯,每 change 分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都 同时 改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。
第二小的值 是 严格大于 最小值的所有值中最小的值。
例如,[2, 3, 4] 中第二小的值是 3 ,而 [2, 2, 4] 中第二小的值是 4 。 给你 n、edges、time 和 change ,返回从节点 1 到节点 n 需要的 第二短时间 。
注意:
你可以 任意次 穿过任意顶点,包括 1 和 n 。 你可以假设在 启程时 ,所有信号灯刚刚变成 绿色 。
示例 1:
输入:n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5
输出:13
解释:
上面的左图展现了给出的城市交通图。
右图中的蓝色路径是最短时间路径。
花费的时间是:
- 从节点 1 开始,总花费时间=0
- 1 -> 4:3 分钟,总花费时间=3
- 4 -> 5:3 分钟,总花费时间=6
因此需要的最小时间是 6 分钟。
右图中的红色路径是第二短时间路径。
- 从节点 1 开始,总花费时间=0
- 1 -> 3:3 分钟,总花费时间=3
- 3 -> 4:3 分钟,总花费时间=6
- 在节点 4 等待 4 分钟,总花费时间=10
- 4 -> 5:3 分钟,总花费时间=13
因此第二短时间是 13 分钟。
示例 2:
输入:n = 2, edges = [[1,2]], time = 3, change = 2
输出:11
解释:
最短时间路径是 1 -> 2 ,总花费时间 = 3 分钟
最短时间路径是 1 -> 2 -> 1 -> 2 ,总花费时间 = 11 分钟
提示:
2 <= n <= 104
n - 1 <= edges.length <= min(2 * 104, n * (n - 1) / 2)
edges[i].length == 2
1 <= ui, vi <= n
ui != vi
不含重复边
每个节点都可以从其他节点直接或者间接到达
1 <= time, change <= 103
来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/se…
分析
使用广度优先搜索获取最短距离和次短距离,这里使用path数组来表示,path[i][0]为按照最短路径的时间,path[i][1]为按照次短路径的时间,只要在广度优先遍历的时候维护最短路径和次短路径的时间即可。
代码
class Solution {
public:
int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
vector<vector<int>> graph(n + 1);
for (auto &e : edges) {
graph[e[0]].push_back(e[1]);
graph[e[1]].push_back(e[0]);
}
vector<vector<int>> path(n + 1, vector<int>(2, INT_MAX));
path[1][0] = 0;
queue<pair<int, int>> q;
q.push({1, 0});
while (!q.empty()) {
auto [cur, timestamp] = q.front();
q.pop();
if(cur == n && path[cur][1] != INT_MAX){
return path[n][1];
}
if (timestamp % (2 * change) >= change) {
timestamp += (2 * change - timestamp % (2 * change));
}
timestamp += time;
for (auto next : graph[cur]) {
if (timestamp < path[next][0]) {
path[next][0] = timestamp;
q.push({next, timestamp});
} else if (timestamp > path[next][0] && timestamp < path[next][1]) {
path[next][1] = timestamp;
q.push({next, timestamp});
}
}
}
return -1;
}
};
深度优先搜索
1219. 黄金矿工
题目 你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。
为了使收益最大化,矿工需要按以下规则来开采黄金:
每当矿工进入一个单元,就会收集该单元格中的所有黄金。 矿工每次可以从当前位置向上下左右四个方向走。 每个单元格只能被开采(进入)一次。 不得开采(进入)黄金数目为 0 的单元格。 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
示例 1:
输入:grid = [[0,6,0],[5,8,7],[0,9,0]] 输出:24 解释: [[0,6,0], [5,8,7], [0,9,0]] 一种收集最多黄金的路线是:9 -> 8 -> 7。
示例 2:
输入:grid = [[1,0,7],[2,0,6],[3,4,5],[0,3,0],[9,0,20]] 输出:28 解释: [[1,0,7], [2,0,6], [3,4,5], [0,3,0], [9,0,20]] 一种收集最多黄金的路线是:1 -> 2-> 3 -> 4 -> 5 -> 6 -> 7。
提示:
1 <= grid.length, grid[i].length <= 15 0 <= grid[i][j] <= 100 最多 25 个单元格中有黄金。
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/pa… 代码 这是一道很常规的深度优先搜索题目
class Solution {
public:
int maxn=0;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
void dfs(vector<vector<int>>& grid, int x, int y, int cnt){
cnt += grid[x][y];
maxn = max(cnt, maxn);
for(int i=0; i < 4; i++){
int tx = x+dx[i], ty = y+dy[i];
if(grid[tx][ty] && tx >= 0 && tx < grid.size() && ty >= 0 && ty < grid[0].size()){
int tmp = grid[tx][ty];
grid[tx][ty] = 0;
dfs(grid, tx, ty, cnt);
grid[tx][ty] = tmp;
}
}
}
int getMaximumGold(vector<vector<int>>& grid) {
for(int i=0; i < grid.size(); i++){
for(int j=0; j < grid[0].size(); j++){
if(grid[i][j]!=0){
int tmp = grid[i][j];
grid[i][j] = 0;
dfs(grid, i, j, 0);
grid[i][j] = tmp;
}
}
}
return maxn;
}
};