BFS基礎
廣度優先搜索(Breadth First Search)用於按離始節點距離、由近到遠漸次訪問圖的節點,可視化BFS
通常使用隊列(queue)結構模擬BFS過程,關於queue見:算法與數據結構基礎 - 隊列(Queue)
最直觀的BFS應用是圖和樹的遍歷,其中圖常用鄰接表或矩陣表示,例如 LeetCode題目 690. Employee Importance:
// LeetCode 690. Employee Importance
/* class Employee { public: int id; int importance; vector<int> subordinates; }; */
// Input: [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1 Output: 11 class Solution { public: int getImportance(vector<Employee*> employees, int id) { int res=0; unordered_map<int,Employee*> m; for(Employee* e:employees) m[e->id]=e; queue<Employee*> q; q.push(m[id]); while(!q.empty()){ Employee* cur=q.front();q.pop(); res+=cur->importance; for(auto s:cur->subordinates) q.push(m[s]); } return res; } };
相關LeetCode題:
513. Find Bottom Left Tree Value 題解
拓撲排序(Topological Sort)也應用了BFS遍歷思想、以達成按依賴關系排序的目的,關於拓撲排序見:算法與數據結構基礎 - 拓撲排序(Topological Sort)
層信息
BFS思路是從某節點層層往外擴展,一些場景下我們需要處理層(level)相關的信息,例如 LeetCode題目 102. Binary Tree Level Order Traversal:
class Solution { public: vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> res; if(root==NULL) return res; queue<TreeNode*> q; q.push(root); while(!q.empty()){ int size=q.size(); vector<int> tmp; for(int i=0;i<size;i++){ //處理當前level TreeNode* cur=q.front();q.pop(); tmp.push_back(cur->val); if(cur->left) q.push(cur->left); if(cur->right) q.push(cur->right); } res.push_back(tmp); } return res; } };
以上代碼不單遍歷了樹節點,還加了按層(level)處理,注意以上代碼與遍歷代碼的細微差別。
相關LeetCode題:
102. Binary Tree Level Order Traversal 題解
429. N-ary Tree Level Order Traversal 題解
111. Minimum Depth of Binary Tree 題解
993. Cousins in Binary Tree 題解
515. Find Largest Value in Each Tree Row 題解
最短距離
BFS另一個重要的應用就是求最短路徑,可以是單點到單點、單點到多點、多點到多點之間的路徑。
當問題出現最小(minimum)、最短(shortest)等字樣時可考慮用BFS求解,一般求解思路是 1/找出滿足條件的起始點,2/由起始點開始進行BFS,3/遇到終點結束。
相關LeetCode題:
以上例題路徑之間沒有差別,更復雜的一種情況是路徑具備權重。對有權圖求解最短路徑,一般情況下會想到Bellman-Ford、Dijkstra算法,而BFS思想是這些算法思想的核心。
相關LeetCode題:
因問題不同、訪問臨近節點的方式各異,在使用BFS時我們可能會遇到重復訪問某一節點的情況。
為了避免重復訪問節點造成死循環,常用hashtable來記錄節點是否已經被訪問。
相關LeetCode題: