一个格子 向周围逐层扩散,适合于求最短路
按层扩散 或者一次一次扩散,按层就是要记下每次距离 (单点弹出,整层弹出)
使用特征为任意节点距离都相同 有单源也有多源
多源扩展典型
class Solution {
public:
int move[5]={-1,0,1,0,-1};
int queue[10001][2];//有两个元素
bool visited[101][101];//保证访问过的不再被访问
int r=0,l=0;
int maxDistance(vector<vector<int>>& grid) {
memset(visited,0,sizeof(visited));
int n=grid.size();
int m=grid[0].size();
int seacount=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(grid[i][j]==1)
{
queue[r][0]=i;
queue[r++][1]=j;
visited[i][j]=1;
}
else
seacount++;
}
}
if(seacount==0||seacount==n*m)
return -1;
int level=0;
while(l<r)
{
level++;
int size=r-l;
for(int i=0;i<size;i++)
{
int x1=queue[l][0];
int y1=queue[l++][1];
for(int j=0;j<4;j++)
{
int xnew=x1+move[j];
int ynew=y1+move[j+1];
if(xnew>=0&&xnew<n&&ynew>=0&&ynew<m&&!visited[xnew][ynew])
{
queue[r][0]=xnew;
queue[r++][1]=ynew;
visited[xnew][ynew]=1;
}
}
}
}
return level-1;
}
};
贴纸拼词
其实先把所有字符串都排序,然后按照拥有的字符来建图,每次把能消去前缀的词选上,然后一直向下扩散
class Solution {
public:
int minStickers(vector<string>& stickers, string target) {
int level=1;
queue<string> q;
vector<vector<string>> graph(26);//类似领接表的方式确定前缀有某个词的字符串
unordered_set<string> set1;
for(string &s:stickers)
{
sort(s.begin(),s.end());
for(int i=0;i<s.length();i++)
{
if(i==0||s[i]!=s[i-1])
graph[s[i]-'a'].push_back(s);
}
}
sort(target.begin(),target.end());
q.push(target);
set1.insert(target);
while(!q.empty())
{
int size1=q.size();
for(int k=0;k<size1;k++)
{
string s=q.front();
q.pop();
//检查字符首位能对的上的
for(string s1:graph[s[0]-'a'])
{
if(next1(s,s1)=="")//s去掉s1中所有字符后
return level;
else if(set1.find(next1(s,s1))==set1.end())//这儿的剪枝必须要有,否则超时
{
q.push(next1(s,s1));
set1.insert(next1(s,s1));
}
}
}
level++;
}
return -1;
}
string next1(string s,string s1)
{
string a;
//两个指针同时扫两个字符串
for(int i=0,j=0;i<s.length();)
{
if(j==s1.length())
a+=s[i++];
else
{
if(s[i]<s1[j])
a+=s[i++];
else if(s[i]>s1[j])
j++;
else
i++,j++;
}
}
return a;
}
};
01 bfs
边的权值只有0和1两种类型,求两点之间最短路
不能用传统的bfs的原因是很可能到了下一级时候节点级数被更改
遇到零的边要从头部进,给了一步修改对的机会
不需要visited标记节点,因为只有边更短的情况下才会去处理
2290. 到达角落需要移除障碍物的最小数目 - 力扣(LeetCode)
一面墙相当于权值为1的边,空地相当于权值为0的边
先把距离全部设为最大
class Solution {
public:
int minimumObstacles(vector<vector<int>>& grid) {
int move[5]={-1,0,1,0,-1};
int m=grid.size();
int n=grid[0].size();
vector<vector<int>> distance(m,vector<int>(n,INT_MAX));
deque<pair<int,int>> d;
distance[0][0]=0;
d.push_back({0,0});
while(!d.empty())
{
pair<int,int> a=d.front();
d.pop_front();
for(int i=0;i<4;i++)
{
int nx=a.first+move[i],ny=a.second+move[i+1];
if(nx>=0&&nx<m&&ny>=0&&ny<n&&distance[nx][ny]>distance[a.first][a.second]+grid[nx][ny])
{
distance[nx][ny]=distance[a.first][a.second]+grid[nx][ny];
if(grid[nx][ny]==0)
d.push_front({nx,ny});
else
d.push_back({nx,ny});
}
}
}
return distance[m-1][n-1];
}
};
二维接雨水
先把边缘的行列都放入小根堆,小根堆根据木桶的高度排,每次弹出一个堆顶元素,结算答案
struct cmp{
bool operator()(vector<int> a,vector<int> b)
{
return a[2]>b[2];
}
};
class Solution {
public:
int trapRainWater(vector<vector<int>>& heightMap) {
int move[5]={-1,0,1,0,-1};
int n=heightMap.size();
int m=heightMap[0].size();
priority_queue<vector<int>,vector<vector<int>>,cmp> q;
vector<vector<bool>> visited(n,vector<bool>(m));
//把所有边缘都进入优先级队列
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(i==0||i==n-1||j==0||j==m-1)
{
q.push({i,j,heightMap[i][j]});
visited[i][j]=1;
}
else
visited[i][j]=0;
}
int ans=0;
while(!q.empty())
{
auto top=q.top();
q.pop();
int i=top[0];
int j=top[1];
int k=top[2];
//弹出时候结算答案
ans+=k-heightMap[i][j];
//向四周扩展
for(int l=0,ni,nj;l<4;l++)
{
ni=i+move[l];
nj=j+move[l+1];
if(ni>=0&&ni<n&&nj>=0&&nj<m&&!visited[ni][nj])
{
q.push({ni,nj,max(k,heightMap[ni][nj])});
visited[ni][nj]=1;
}
}
}
return ans;
}
};
单词接龙
先把所有单词存入一个哈希表,便于去直接查找需要变化的单词
class Solution {
public:
unordered_set<string> dict;
unordered_set<string> curlevel, nextlevel;
unordered_map<string, vector<string>> graph;
vector<string> path;
vector<vector<string>> ans;
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
dict = unordered_set<string>(wordList.begin(), wordList.end());
if (beginWord == endWord) {
return {{beginWord}};
}
if (dict.find(endWord) == dict.end()) {
return ans;
}
if (bfs(beginWord, endWord)) {
dfs(endWord, beginWord);
}
return ans;
}
bool bfs(string beginWord, string endWord) {
bool find1 = false;
curlevel.insert(beginWord);
while (!curlevel.empty()) {
// 移除当前层的单词,避免冗余访问
for (string s : curlevel) {
dict.erase(s);
}
for (string s : curlevel) {
string w = s;
for (int i = 0; i < s.length(); i++) {
char old = w[i];
for (char ch = 'a'; ch <= 'z'; ch++) {
w[i] = ch;
if (dict.find(w) != dict.end() && ch != old) {
// 构建路径图
graph[w].push_back(s);
if (w == endWord) {
find1 = true; // 找到目标单词
}
nextlevel.insert(w);
}
}
w[i] = old; // 恢复单词
}
}
if (find1) {
return true;
} else {
curlevel = nextlevel;
nextlevel.clear();
}
}
return false;
}
void dfs(string beginWord, string endWord) {
path.push_back(beginWord);
if (beginWord == endWord) {
ans.push_back(vector<string>(path.rbegin(), path.rend()));
} else {
if (graph.find(beginWord) != graph.end()) {
for (string s : graph[beginWord]) {
dfs(s, endWord);
}
}
}
path.pop_back(); // 回溯
}
};