bfs 的核心思想應該不難理解的,就是把一些問題抽象成圖,從乙個點開始,向四周開始擴散。一般來說,我們寫 bfs 演算法都是用「佇列」這種資料結構,每次將乙個節點周圍的所有節點加入佇列。
特點:bfs 找到的路徑一定是最短的,但代價就是空間複雜度可能比 dfs 大很多
問題的本質就是讓你在一幅「圖」中找到從起點start
到終點target
的最近距離
框架:
// 計算從起點 start 到終點 target 的最近距離
int bfs(node start, node target) }}
/* 劃重點:更新步數在這裡 */
step++;}}
佇列q
:bfs 的核心資料結構;cur.adj()
泛指cur
相鄰的節點,比如說二維陣列中,cur
上下左右四面的位置就是相鄰節點;visited
的主要作用是防止走回頭路,大部分時候都是必須的,但是像一般的二叉樹結構,沒有子節點到父節點的指標,不會走回頭路就不需要visited
。
力扣第 111 題「 二叉樹的最小深度」
思路:簡單,與框架差不多,也可以使用深度優先搜尋。
class solution
//未找到 就將cur的子樹加入佇列
if(cur->left!=nullptr)q.push(cur->left);
if(cur->right!=nullptr)q.push(cur->right);
}//查詢過一行那麼深度就+1
depth++;
}return depth;}};
書中解析較為詳細:
這裡注意這個while
迴圈和for
迴圈的配合,while
迴圈控制一層一層往下走,for
迴圈利用sz
變數控制從左到右遍歷每一層二叉樹節點:
對於兩個問題的解答:
1、為什麼 bfs 可以找到最短距離,dfs 不行嗎?
首先,你看 bfs 的邏輯,depth
每增加一次,佇列中的所有節點都向前邁一步,這保證了第一次到達終點的時候,走的步數是最少的。
dfs 不能找最短路徑嗎?其實也是可以的,但是時間複雜度相對高很多。你想啊,dfs 實際上是靠遞迴的堆疊記錄走過的路徑,你要找到最短路徑,肯定得把二叉樹中所有樹杈都探索完才能對比出最短的路徑有多長對不對?而 bfs 借助佇列做到一次一步「齊頭並進」,是可以在不遍歷完整棵樹的條件下找到最短距離的。
2、既然 bfs 那麼好,為啥 dfs 還要存在?
bfs 可以找到最短距離,但是空間複雜度高,而 dfs 的空間複雜度較低。
還是拿剛才我們處理二叉樹問題的例子,假設給你的這個二叉樹是滿二叉樹,節點數為n
,對於 dfs 演算法來說,空間複雜度無非就是遞迴堆疊,最壞情況下頂多就是樹的高度,也就是o(logn)
。
但是你想想 bfs 演算法,佇列中每次都會儲存著二叉樹一層的節點,這樣的話最壞情況下空間複雜度應該是樹的最底層節點的數量,也就是n/2
,用 big o 表示的話也就是o(n)
。
由此觀之,bfs 還是有代價的,一般來說在找最短路徑的時候使用 bfs,其他時候還是 dfs 使用得多一些(主要是遞迴**好寫)。
這是力扣第 752 題「 開啟轉盤鎖」,比較有意思:
**:作者給出的是j**a型別,這是我的c++**
class solution
}/* 在這裡增加步數 */
step++;
// temp 相當於 q1
// 這裡交換 q1 q2,下一輪 while 就是擴散 q2
q1 = q2;
q2 = temp;
}return -1;
}
雙向 bfs 還是遵循 bfs 演算法框架的,只是不再使用佇列,而是使用 hashset 方便快速判斷兩個集合是否有交集。
另外的乙個技巧點就是while 迴圈的最後交換q1
和q2
的內容,所以只要預設擴散q1
就相當於輪流擴散q1
和q2
。
其實雙向 bfs 還有乙個優化,就是在 while 迴圈開始時做乙個判斷:
// ...
while (!q1.isempty() && !q2.isempty())
// ...
為什麼這是乙個優化呢?
因為按照 bfs 的邏輯,佇列(集合)中的元素越多,擴散之後新的佇列(集合)中的元素就越多;在雙向 bfs 演算法中,如果我們每次都選擇乙個較小的集合進行擴散,那麼占用的空間增長速度就會慢一些,效率就會高一些。
不過話說回來,無論傳統 bfs 還是雙向 bfs,無論做不做優化,從 big o 衡量標準來看,時間複雜度都是一樣的,只能說雙向 bfs 是一種 trick,演算法執行的速度會相對快一點,掌握不掌握其實都無所謂。最關鍵的是把 bfs 通用框架記下來,反正所有 bfs 演算法都可以用它套出解法。
第一章 核心套路篇 之 BFS演算法套路框架
bfs breath first search 和dfs depth first search 是兩種十分常用的演算法,其中dfs演算法可以認為是回溯演算法 bfs演算法和核心就是將問題抽象成圖,從一點開始進行擴散,一般來說寫bfs的時候均使用佇列,每次將乙個結點周圍的所有結點加入到佇列中 bfs相...
BFS演算法框架
bfs演算法框架 bfs的核心思想,就是把一些問題抽象成圖,從乙個節點開始,向四周擴散。一般來說,寫bfs都是用 佇列 這個資料結構,每次將乙個節點周圍的節點加入到隊尾。先舉例 下 bfs 出現的常 場景好吧,問題的本質就是讓你在 幅 圖 中找到從起點 start 到終點 target 的最近距離,...
BFS 廣度搜尋 演算法框架
一般bfs和資料結構中的佇列聯絡比較緊密 1.演算法框架 計算的是迷宮,從起點出發,到達終點,走的步數。計算從起點 start 到終點 target 的最近距離 intbfs node start,node target 劃重點 更新步數在這裡 step 2.二叉樹的最小高度 套模板 二叉樹的最小深...