前言
进入图论部分难度明显提升了一大截,思路想不到一点……
一、宽度优先遍历
1.内容
宽度优先遍历主要用于在图上求最短路。
(1)特点
宽度优先遍历的特点就是逐层扩展,最短路即层数
(2)使用条件
无向图且任意节点间距离相等
(3)注意
进入队列后需标记状态防止重复入队。
可剪枝!!可单源头可多源头!!
(4)难点
主要难点在于节点如何找路、路的展开以及剪枝方法。
2.题目
(1)地图分析
class Solution {
public:
//移动 -> 上下左右
vector<int>move={-1,0,1,0,-1};
int maxDistance(vector<vector<int>>& grid) {
int n=grid.size();
vector<vector<bool>>visited(n,vector<bool>(n));
queue<pair<int,int>>node;
int seas=0;
//初始化
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(grid[i][j]==1)//陆地
{
visited[i][j]=true;
node.push(make_pair(i,j));
}
else//海洋
{
seas++;
}
}
}
//特例
if(seas==0||seas==n*n)
{
return -1;
}
//统计
int level=0;
while(!node.empty())
{
level++;
int size=node.size();
for(int i=0,x,y,nx,ny;i<size;i++)
{
x=node.front().first;
y=node.front().second;
node.pop();
for(int j=0;j<4;j++)
//j=0:上
//j=1:下
//j=2:左
//j=3:右
{
nx=x+move[j];
ny=y+move[j+1];
if(nx>=0&&nx<n&&ny>=0&&ny<n&&grid[nx][ny]==0&&!visited[nx][ny])
{
visited[nx][ny]=true;
node.push(make_pair(nx,ny));
}
}
}
}
return level-1;//到最后还被多加了一次
}
};
这个题主要是引入节点向周围找路的方法。
整体思路就是从每个陆地往外进行宽度优先遍历,遇到海就“感染”入队,最后返回层数-1即可。
首先,要遍历每个陆地入队,与此同时还可以顺便统计海洋数量。若全为海或者全为陆地就直接返回。之后进行宽度优先遍历统计level层数,每次从队列里取队列的size个,即当前层的所有节点,然后每个节点向外扩。注意这里向外扩的写法,设置move数组为-1,0,1,0,-1,之后每来到一个位置就让下一步的nx=x+move[j],ny=y+move[j+1],这样就能实现向上下左右四个方向扩。当下一步的位置有效时,就记录状态然后入队。
(2)贴纸拼词
class Solution {
public:
//邻接表建图
vector<vector<string>>graph;
int minStickers(vector<string>& stickers, string target) {
int n=stickers.size();
graph.resize(26);//能消目标某字母的字符串
//路的展开 -> 用每个贴纸会导致不同的剩余情况
for(int i=0;i<n;i++)
{
//排序字符串 -> 只考虑词频和字母
sort(stickers[i].begin(),stickers[i].end());
//建图
for(int j=0;j<stickers[i].length();j++)
{
//统计能消的字符
if(j==0||stickers[i][j]!=stickers[i][j-1])//不重复加
{
graph[stickers[i][j]-'a'].push_back(stickers[i]);
}
}
}
//排序
sort(target.begin(),target.end());
set<string>visited;//剩余字符串去重
queue<string>node;
visited.insert(target);
node.push(target);