LeetCode刷題之BFS和DFS

LeetCode刷題之BFS和DFS

廣度優先搜索(BFS)

主要用於樹的層序遍歷或圖的最短路徑尋找,主要使用隊列queue來完成。
①樹的層序遍歷:使用隊列保存未被檢測的結點,結點按照寬度優先的次序被訪問和進出隊。
②有向無環圖的最短路徑查找:由於有向無環圖的某個節點的next節點可能會與另一個節點的next節點重複,所以我們需要記錄已訪問過的節點

//根節點與目標節點之間的最短路徑長度
int BFS(Node root, Node target) {
    Queue<Node> queue;  // 用來存放節點的隊列
    Set<Node> used;     // 用來存放已經使用過的節點
    int step = 0;       // 步長
    
    //1:初始化
    add root to queue;
    add root to used;
    
    //2:開始進行BFS
    while (queue is not empty) {
        step = step + 1;
        
        //隊列中已經存放的節點個數
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                if (next is not in used) {
                    add next to queue;
                    add next to used;
                }
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}

深度優先搜索(DFS)

一直往深處走,直到找到解或者走不下去爲止,主要用於樹的遍歷(前序遍歷,中序遍歷,後序遍歷)或者圖的搜索問題或者回溯算法問題。
①樹的遍歷:一直向葉子節點遍歷,直至遇到葉子節點表示此根節點到這個葉子節點的路徑已經訪問完,需要訪問根節點到下一個葉子節點的路徑。(當然遍歷順序主要取決於遍歷的方式,比如前序遍歷(根左右)、後序遍歷(左根右)、後序遍歷(左右根))

②圖的搜索問題:上面我們使用了BFS來解決圖的最短路徑問題,同時我們也可以使用DFS來實現圖的最短路徑尋找。在這裏我們分別提供遞歸版模板和用stack的迭代版模板:
遞歸

boolean DFS(Node cur, Node target, Set<Node> visited) {
    return true if cur is target;
    for (next : each neighbor of cur) {
        if (next is not in visited) {
            add next to visted;
            return true if DFS(next, target, visited) == true;
        }
    }
    return false;
}

非遞歸

boolean DFS(int root, int target) {
    Set<Node> visited;
    Stack<Node> s;
    add root to s;
    while (s is not empty) {
        Node cur = the top element in s;
        return true if cur is target;
        for (Node next : the neighbors of cur) {
            if (next is not in visited) {
                add next to s;
                add next to visited;
            }
        }
        remove cur from s;
    }
    return false;
}

回溯法:回溯法使用DFS的策略來尋找所有可行解或者最優解,也就是回溯法的所有解可以構成一個解空間樹或者解空間圖,所以對於這個解空間樹或圖,我們就使用DFS策略了

//choicelist:表示可以進行選擇的列表,相當於樹中可選用左節點還是右結點
//track:表示爲決策路徑,相當於在樹中爲根節點到某個葉子節點的路徑
//result:表示存放根節點到所有葉子節點的所有路徑
backtrack(choicelist,track,result)
{
	if(track is ok)result.push(track);
	else{
		for choice in choicelist:
			//choose過程:選擇一個choice加入track,相當於在樹中選擇一個節點加入路徑
			backtrack(choices,track,result);//進入下一步決策
			//unchoose過程:從track中撤銷上面的選擇,相當於在樹中移除上一次選擇的節點
	}
}

應用與風險:
1)DFS多用於連通性問題因爲其運行思想與人腦的思維很相似,故解決連通性問題更自然。
2)BFS多用於解決最短路問題,其運行過程中需要儲存每一層的信息,所以其運行時需要儲存的信息量較大,如果人腦也可儲存大量信息的話,理論上人腦也可運行BFS。
3)多數情況運行BFS所需的內存會大於DFS需要的內存(DFS一次訪問一條路,BFS一次訪問多條路)
4)風險:DFS容易爆棧(棧不易”控制”),BFS通過控制隊列可以很好解決”爆隊列”風險。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章