宽度优先遍历扩展

一个格子 向周围逐层扩散,适合于求最短路

按层扩散 或者一次一次扩散,按层就是要记下每次距离 (单点弹出,整层弹出)

使用特征为任意节点距离都相同   有单源也有多源

多源扩展典型

1162. 地图分析 - 力扣(LeetCode)

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;
    }
};

贴纸拼词

691. 贴纸拼词 - 力扣(LeetCode)

其实先把所有字符串都排序,然后按照拥有的字符来建图,每次把能消去前缀的词选上,然后一直向下扩散

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]; 
    }
};

二维接雨水

 407. 接雨水 II - 力扣(LeetCode)

先把边缘的行列都放入小根堆,小根堆根据木桶的高度排,每次弹出一个堆顶元素,结算答案

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;
    }
};

单词接龙

126. 单词接龙 II - 力扣(LeetCode)

先把所有单词存入一个哈希表,便于去直接查找需要变化的单词

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(); // 回溯
    }
};

### 宽度优先遍历与深度优先遍历的区别 #### 算法机制差异 宽度优先遍历(BFS)遵循逐层扩展的原则,从起始节点出发,依次访问其所有邻接节点,再按相同方式处理这些新发现的节点直到全部节点被访问完毕[^1]。相比之下,深度优先遍历(DFS)则采取深入探索的方式,在遇到未访问过的分支时会尽可能深地沿着该路径前进直至无法继续为止,随后回溯至上一可选位置并重复此过程。 对于具体实现而言: - **BFS**通常借助队列数据结构完成操作,每次都将当前层次的所有子节点加入到待处理列表末端; - **DFS**更多依赖栈或递归来管理状态转移序列,每当进入新的子树前都会保存现有环境以便后续返回时恢复现场[^3]。 ```python from collections import deque def bfs(graph, start): visited = set() queue = deque([start]) while queue: vertex = queue.popleft() if vertex not in visited: print(vertex) visited.add(vertex) for neighbor in graph[vertex]: if neighbor not in visited: queue.append(neighbor) def dfs(graph, start, visited=None): if visited is None: visited = set() stack = [start] while stack: vertex = stack.pop() if vertex not in visited: print(vertex) visited.add(vertex) stack.extend( neighbor for neighbor in reversed(graph[vertex]) if neighbor not in visited ) ``` #### 应用场景对比 当面对连通性检测、最短路径查找等问题时,由于BFS能够保证首次到达目标节点所经过的距离是最优解之一,故而更适合此类需求;而在涉及拓扑排序、强连通分量识别以及某些特定模式匹配的情况下,则往往更倾向于采用能快速触及深层结构特性的DFS方法[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值