dfs沒有固定的演算法模版,更像是一種演算法思想。是一種經常使用的搜尋演算法。一般碰到讓讓求全部組合數,或者全排列這類問題,會使用dfs。從資料結構的角度來看,一般可能會出現:1. 在樹上的dfs;2. 在圖上的dfs;3. 在矩陣上的dfs。
在**的實現上,一般採用遞迴來實現。
dfs就像乙個非常執著的人,它總會順著一條路徑一直往下(深處)走,只有實在走不下去的時候,它才會往回返(回溯),而且在往回返的時候也還在看是否還能往下(深處)走。是乙個非常值得我們學習的人。
額外的話:在思考dfs的時候,我們最好腦中或者紙上有一張遞迴搜尋的樹,類似下面這個樣子,方便自己思考。
碰到讓你找所有方案的題,一定是dfs;90%dfs的題,要麼是排列要麼是組合。
此外,如果面試官不特別要求的話,dfs都可以使用遞迴(recursion)的方式來實現。
問題模型:求出所有滿足條件的「組合」
判斷條件:組合中的元素是順序無關的。
時間複雜度:與2^n相關。
這裡說明幾種一般情況:
情況1: 求一串數字沒有任何重複的全部組合數。
比如求[1, 2, 3]沒有任何重複的全部組合數。
class solution
return;
}vector> combination(vector& nums)
};
上面這段**執行之後,result中為[,[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]]
,可以看出是沒有重複的全部組合數。這裡有兩個關鍵的點,乙個是dfs函式中for迴圈i的起始為i = start
,另乙個為for迴圈中dfs遞迴函式的呼叫時最後乙個傳入引數為i + 1
這使得start一路向前,不會出現後面數字串中後面數字比前面數字小的組合出現,比如不會出現[2, 1],或者[1, 3, 2]。
例題:leetcode 78. 子集
情況2:情況1只是便於我們理解,實際中會出現各種重複種類需要我們稍微特殊處理一下。比如有一種簡單的重複為:乙個數字允許出現2次,比如可以有[2, 2, 3]這種型別。
並且實際求組合的題,都是要求你尋找滿足某種條件的全部組合,因此也會稍微需要一些多的判斷。比如下面這道題讓你尋找陣列中和為target的全部組合。
題目及解答的鏈結在這裡:leetcode 39. 組合總和
這裡的關鍵點在於:因為乙個數字可以出現2次,所以我們需要稍微做一點改變。將上面**中dfs遞迴函式的呼叫dfs(result, nums, combination, i + 1);
語句中最後乙個傳入引數改為i
,而不是原來的i + 1
。
其它情況:實際中還會有一些別的種類的重複或者需求,但以上面的為基礎去理解和實現可能會容易一些,下面也給出了幾道組合類問題的題目。
組合例題:
【深度優先搜尋dfs】lintcode 135. 數字組合
【深度優先搜尋dfs】lintcode 153. 數字組合 ii
【深度優先搜尋dfs】lintcode 136. 分割回文串
(2)排列
問題模型:求出所有滿足條件的「排列」。
判斷條件:組合中的元素是順序「相關」的。
時間複雜度:與 n! 相關。
排列和組合有些不同,排列和順序有關,所以要求乙個陣列[1, 2, 3]的全排列的話,[1, 2, 3]和[1, 3, 2], [2, 3, 1]等都是有效的全排列。所以它的dfs函式中for迴圈的起始為i = 0
(關鍵點)。但它也需要去一種型別的重複,那就是不允許出現同乙個數字出現多次,比如不允許[1, 1, 2],[2, 3, 3]。針對這種重復,在全排列問題中常見的去重方法有兩種:1. 使用set去重;2. 開乙個bool陣列。基本思想是將已經出現的數字標記一下,下面再次出現的時候就跳過,這樣就不會出現[1, 1, 2]這種情況。
下面是一些全排列問題的題目。
排列例題:
【寬度優先搜尋bfs】lintcode 120. 單詞接龍
【深度優先搜尋dfs】lintcode 16. 帶重複元素的排列
劍指 offer 38. 字串的排列
【深度優先搜尋dfs】lintcode 33. n皇后問題
圖上搜尋的例題:
1、【寬度優先搜尋bfs】lintcode 120. 單詞接龍(這其實是一道寬度優先搜尋的題,只是為了引出下面的第2題)
2、【深度優先搜尋dfs】lintcode 121.單詞接龍ii
1、【深度優先搜尋dfs】leetcode 79. 單詞搜尋
深度優先搜尋DFS
作為搜尋演算法的一種,dfs對於尋找乙個解的 np 包括npc 問題作用很大。但是,搜尋演算法畢竟是 時間複雜度是o n 的階乘級演算法,它的效率比較低,在資料規模變大時,這種演算法就顯得力不從心了。關於深度優先搜尋的效率問題,有多種解決方法。最具有通用性的是剪枝 prunning 也就是去除沒有用...
深度優先搜尋 DFS
深度優先搜尋 縮寫dfs 有點類似廣度優先搜尋,也是對乙個連通圖進行遍歷的演算法。它的思想是從乙個頂點v 0開始,沿著一條路一直走到底,如果發現不能到達目標解,那就返回到上乙個節點,然後從另一條路開始走到底,這種盡量往深處走的概念即是深度優先的概念。你可以跳過第二節先看第三節,還是引用上篇文章的樣例...
深度優先搜尋(dfs)
深度優先搜尋的一般步驟 1 從頂點v出發,訪問v。2 找出剛才訪問過的頂點的第乙個未被訪問的鄰接點,訪問該頂點。以該頂點為新頂點,重複此步驟,直到剛訪問的頂點沒有沒有未被訪問過的鄰接點為止。3 返回前乙個訪問過的仍有未被訪問過的鄰接點的頂點,找出該頂點的下乙個未被訪問過的鄰接點,訪問該頂點。4 重複...