题目:
1293. 网格中的最短路径链接
1294.
思路:
这题我们可以采用bfs和dfs来做,首先我们需要明白bfs由于相当于没有回溯的过程,因此bfs是不需要遍历完所有节点就可以找到到目的的最短路径,但是由于dfs有借助于回溯的思想,因此是需要遍历完所有节点才可以知道最短路径长度。
方法一bfs:思路
首先,我们采用seen这个二维的vector里面存放着从起始点以相同的步数走到当前位置过程中,这个位置存放的最小的障碍obstacle数目(由于后面做了剪枝,因此只要obstacle数目>k ,我们就认为当前存放的obstacle=INT_MAX),
我们知道借助队列进行bfs的第一步是放入一个位置到队列中,下列代码
qu.push({0,0,0});//start_i,start_j,obstacleNumbers
{0,0,0} 第一个,和第二个0代表起始位置 start_i,start_j,第三个代表其实的障碍数目,由于题目中有grid[0][0] == grid[m-1][n-1] == 0 可以知道最开始的起始位置是没有障碍物的,因此obstacleNumbers=0;
我认为这道题是关于消除障碍的bfs重要的第二步,和以往的bfs中的used中的不同(普通的迷宫问题可以根据used判断是否可以走)。
下列代码
if(isArea(grid,temp_i,temp_j))
{
int newObstacle=current[2]+grid[temp_i][temp_j];
int oldObstacle=seen[temp_i][temp_j];
if(newObstacle<oldObstacle&&newObstacle<=k)
{
qu.push({temp_i,temp_j,newObstacle});
seen[temp_i][temp_j]=newObstacle;
}
}
当我们发现newObstacle<seen[temp_i][temp_j] 我们需要更新seen ,因为还有比之前存的相同步数到达这个位置更小的障碍obstacle数目。(也就是到达此位置我们碰到的1的数目可以更少。)不然就是不可走(不用入队列)
方法二dfs:思路 leetcode会超时
dfs其实就是传入变量时有 k 这个k代表还剩多少次可以消除障碍的机会。因此这样的话在dfs我们需要注意
- 没有障碍时(grid[temp_i][temp_j] == 0)可以直接dfs,
- 有障碍时(grid[temp_i][temp_j] == 1){k–;然后dfs}
if (grid[temp_i][temp_j] == 0)
{
dfs(grid, used, temp_i, temp_j, k, step);
used[temp_i][temp_i] = false;
}
if (k > 0 && grid[temp_i][temp_j] == 1)
{
k--;
dfs(grid, used, temp_i, temp_j, k, step);
k++;
}
代码:
方法一:bfs
class Solution {
private:
vector<vector<int>> dxy{{0,-1},{-1,0},{0,1},{1,0}};
bool isArea(vector<vector<int>>& grid,int temp_i,int temp_j)
{
if(temp_i<0||temp_i>=grid.size()||temp_j<0||temp_j>=grid[0].size()) return false;
return true;
}
public:
int shortestPath(vector<vector<int>>& grid, int k)
{
//一般来说 bfs的路径会是最短路径 seen是存放着与迷宫大小同等维度的,里面的数代表着从开始到当前节点的最小阻碍数目
vector<vector<int>> seen(grid.size(),vector<int>(grid[0].size(),INT_MAX));
int step=0;
queue<vector<int>> qu;
qu.push({0,0,0});//start_i,start_j,obstacleNumbers
while(!qu.empty())
{
int n=qu.size();
for(int i=0;i<n;i++)
{
vector<int> current=qu.front();
qu.pop();
if(current[0]==grid.size()-1&¤t[1]==grid[0].size()-1)
{
return step;
}
for(int j=0;j<dxy.size();j++)
{
int temp_i=current[0]+dxy[j][0];
int temp_j=current[1]+dxy[j][1];
if(isArea(grid,temp_i,temp_j))
{
int newObstacle=current[2]+grid[temp_i][temp_j];
int oldObstacle=seen[temp_i][temp_j];
if(newObstacle<oldObstacle&&newObstacle<=k)
{
qu.push({temp_i,temp_j,newObstacle});
seen[temp_i][temp_j]=newObstacle;
}
}
}
}
step++;//随着每次队列向外面扩展一次,步数也会加一
}
return -1;
}
};
方法二dfs:思路 leetcode会超时
class Solution {
private:
int global_min = INT_MAX;
vector<vector<int>> dxy{ {0,1},{1,0},{0,-1},{-1,0} };
bool isArea(vector<vector<int>>& grid,int &temp_i,int &temp_j)
{
if (temp_i < 0 || temp_i >= grid.size() || temp_j < 0 || temp_j >= grid[0].size()) return false;
return true;
}
void dfs(vector<vector<int>>&grid, vector<vector<bool>>&used, int current_i, int current_j, int &k,int &step)
{
// cout<<"current_i="<<current_i<<"current_j="<<current_j<<endl;
if (current_i== grid.size()-1&¤t_j==grid[0].size()-1)
{
global_min = min(global_min,step);
// cout<<"step="<<step<<endl;
return;
}
for (int i=0;i<dxy.size();i++)
{
int temp_i = current_i + dxy[i][0];
int temp_j = current_j + dxy[i][1];
if (isArea(grid, temp_i, temp_j) && used[temp_i][temp_j] == false)//&&grid[start_i][start_j]==0
{
used[temp_i][temp_j] = true;
step++;
if (grid[temp_i][temp_j] == 0)
{
dfs(grid, used, temp_i, temp_j, k, step);
used[temp_i][temp_i] = false;
}
if (k > 0 && grid[temp_i][temp_j] == 1)
{
k--;
dfs(grid, used, temp_i, temp_j, k, step);
k++;
}
step--;
used[temp_i][temp_j] = false;
}
}
}
public:
int shortestPath(vector<vector<int>>& grid, int k)
{
// cout<<"raw="<<grid.size()<<"col="<<grid[0].size()<<endl;
vector<vector<bool>> used (grid.size(), vector<bool>(grid[0].size(), false));
int start_i = 0;
int start_j = 0;
int step = 0;
used[start_i][start_j] == true;
dfs(grid, used, start_i, start_j, k, step);
return global_min==INT_MAX?-1:global_min;
}
};