持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情
广度优先搜索
1020. 飞地的数量
给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。
一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。
返回网格中 无法 在任意次数的移动中离开网格边界的陆地单元格的数量。
示例 1:
输入:grid = [[0,0,0,0],[1,0,1,0],[0,1,1,0],[0,0,0,0]] 输出:3 解释:有三个 1 被 0包围。一个 1 没有被包围,因为它在边界上。
示例 2:
输入:grid = [[0,1,1,0],[0,0,1,0],[0,0,1,0],[0,0,0,0]] 输出:0 解释:所有 1 都在边界上或可以到达边界。
提示:
m == grid.length n == grid[i].length 1 <= m, n <= 500 grid[i][j] 的值为 0或 1
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/nu…
代码
从边界开始广度优先即可
class Solution {
public:
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int numEnclaves(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
queue<pair<int,int>> q;
//cout<<m<<" "<<n<<endl;
for(int i=0; i < m; i++){
if(grid[i][0]){
grid[i][0] = 0;
q.push(make_pair(i, 0));
}
if(grid[i][n-1]){
grid[i][n-1] = 0;
q.push(make_pair(i, n-1));
}
}
for(int i=0; i < n; i++){
if(grid[0][i]){
grid[0][i] = 0;
q.push(make_pair(0, i));
}
if(grid[m-1][i]){
grid[m-1][i] = 0;
q.push(make_pair(m-1, i));
}
}
while(!q.empty()){
auto [x, y] = q.front();
q.pop();
for(int i=0; i < 4; i++){
int tx, ty;
tx = x + dx[i];
ty = y + dy[i];
if(tx >= 0 && tx < m && ty >= 0 && ty < n){
//cout<<x<<" "<<y<<" "<<tx<<" "<<ty<<endl;
if(grid[tx][ty]){
grid[tx][ty]= 0;
q.push(make_pair(tx, ty));
}
}
}
}
int ans=0;
for(int i=0; i < m; i++){
for(int j=0; j < n; j++){
if(grid[i][j]){
ans++;
}
}
}
return ans;
}
};
1345. 跳跃游戏 IV
题目
给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。
每一步,你可以从下标 i 跳到下标:
i + 1 满足:i + 1 < arr.length i - 1 满足:i - 1 >= 0 j 满足:arr[i] == arr[j] 且 i != j 请你返回到达数组最后一个元素的下标处所需的 最少操作次数 。
注意:任何时候你都不能跳到数组外面。
示例 1:
输入:arr = [100,-23,-23,404,100,23,23,23,3,404]
输出:3
解释:那你需要跳跃 3 次,下标依次为 0 --> 4 --> 3 --> 9 。下标 9 为数组的最后一个元素的下标。
示例 2:
输入:arr = [7]
输出:0
解释:一开始就在最后一个元素处,所以你不需要跳跃。
示例 3:
输入:arr = [7,6,9,6,9,6,9,7]
输出:1
解释:你可以直接从下标 0 处跳到下标 7 处,也就是数组的最后一个元素处。
示例 4:
输入:arr = [6,1,9]
输出:2
示例 5:
输入:arr = [11,22,7,7,7,7,7,7,7,22,13]
输出:3
提示:
1 <= arr.length <= 5 * 10^4 -10^8 <= arr[i] <= 10^8
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/ju…
分析
从题目可以看出这道题可以使用广度优先搜索解决,需要的步数就是遍历到结尾时的层数。但是这里的问题在于超时,因为直接暴力的搜索会有重复的结点访问,这一部分是可以通过剪枝优化。
因为通过暴力搜索的完整图从理论上有可能是无穷的,所以在这里为了理解方便只画图中部分的情况
如下图所示
为了解决这个问题我们可以对结点做标记,如果已经访问过则不在访问,代码中的
set<int> s和m.erase的目的都是为了移除掉已访问的结点以进行剪枝,从而优化时间
代码
struct Node{
int idx;
int level;
};
class Solution {
public:
int minJumps(vector<int>& arr) {
map<int, vector<int>> m;
set<int> s;
queue<Node> q;
for(int i=0; i < arr.size(); i++){
m[arr[i]].push_back(i);
}
Node n;
n.idx = 0;
n.level = 0;
q.push(n);
while(!q.empty()){
Node p=q.front();
q.pop();
if(p.idx == arr.size()-1){
return p.level;
}
s.insert(p.idx);
if(m.count(arr[p.idx])){
for(int i=0; i < m[arr[p.idx]].size(); i++){
if(!s.count(m[arr[p.idx]][i])){
Node tmp;
tmp.idx = m[arr[p.idx]][i];
tmp.level = p.level + 1;
q.push(tmp);
}
}
m.erase(arr[p.idx]);
}
if(p.idx > 0 && !s.count(p.idx-1)){
Node tmp;
tmp.idx = p.idx - 1;
tmp.level = p.level + 1;
q.push(tmp);
}
if(p.idx <= arr.size()-1 && !s.count(p.idx+1)){
Node tmp;
tmp.idx = p.idx + 1;
tmp.level = p.level + 1;
q.push(tmp);
}
}
return -1;
}
};