『算法』『數(shù)據(jù)結(jié)構(gòu)』 淺談回溯算法(DFS 深度優(yōu)先算法)叠聋,理解程序員必懂必會的計算機常見算法——回溯算法(DFS 深度優(yōu)先算法)

基本認識

回溯算法(DFS 深度優(yōu)先算法)實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解盏阶,當發(fā)現(xiàn)已不滿足求解條件時晒奕,就“回溯”返回,嘗試別的路徑名斟∧曰郏回溯法是一種選優(yōu)搜索法,按選優(yōu)條件向前搜索砰盐,以達到目標闷袒。但當探索到某一步時,發(fā)現(xiàn)原先選擇并不優(yōu)或達不到目標岩梳,就退回一步重新選擇囊骤,這種走不通就退回再走的技術(shù)為回溯法,而滿足回溯條件的某個狀態(tài)的點稱為“回溯點”冀值。

基本思想與原理

回溯法(DFS 深度優(yōu)先算法)簡單來說就是按照深度優(yōu)先的順序也物,窮舉所有可能性的算法,但是回溯算法比暴力窮舉法更高明的地方就是回溯算法可以隨時判斷當前狀態(tài)是否符合問題的條件列疗。一旦不符合條件滑蚯,那么就退回到上一個狀態(tài),省去了繼續(xù)往下探索的時間。
換句話說告材,回溯法可以理解為通過選擇不同的岔路口尋找目的地坤次,一個岔路口一個岔路口的去嘗試找到目的地。如果走錯了路斥赋,繼續(xù)返回來找到岔路口的另一條路缰猴,直到找到目的地。省去了在錯路上走下去的時間疤剑。

適用的問題

如果一個問題是搜索求解類的問題滑绒,而且該問題的解是樹狀結(jié)構(gòu)(不斷擴張式向量),該題就可以考慮使用回溯算法骚露。

回溯算法的典型例題和適用特點

加粗樣式

求解的步驟與模板

回溯函數(shù)的三個組成部分:

1.回溯出口:當找到了一個問題的解時蹬挤,存儲該解。

2.回溯主體:就是遍歷當前的狀態(tài)的所有子節(jié)點棘幸,并判斷下一個狀態(tài)是否是滿足問題條件的焰扳,如果滿足問題條件,那么進入下一個狀態(tài)误续。

3.狀態(tài)返回:如果當前狀態(tài)不滿足條件吨悍,那么返回到前一個狀態(tài)。

回溯函數(shù)萬能模板:

以python3為例:

def backtrack ( 參數(shù) ):

    #回溯出口
    if ( 滿足題意了 ):
        計數(shù)或進行其他操作
        return True   #有時可以省略
    
    #回溯主體
    for( 查找當前節(jié)點的周圍的節(jié)點 )
        進行其他的操作;
        標記已經(jīng)搜索過的節(jié)點
        backtrack( 下一次搜索的節(jié)點 )
    #狀態(tài)返回
        取消標記;
    return False    #有時可以省略

引例部分

八皇后問題:
八皇后問題是一個古老而著名的問題蹋嵌,是回溯算法的典型案例育瓜。該問題是國際西洋棋棋手馬克斯·貝瑟爾于1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊栽烂,即任意兩個皇后都不能處于同一行躏仇、同一列或同一斜線上,問有多少種擺法腺办?

解題思路:
1.從棋盤的第一行開始焰手,從第一個位置開始,依次判斷當前位置是否能夠放置皇后怀喉,判斷的依據(jù)為:同該行之前的所有行中皇后的所在位置進行比較书妻,如果在同一列,或者在同一條斜線上(斜線有兩條躬拢,為正方形的兩個對角線)躲履,都不符合要求,繼續(xù)檢驗后序的位置聊闯。
2.如果該行所有位置都不符合要求工猜,則回溯到前一行,改變皇后的位置菱蔬,繼續(xù)試探域慷。
3.如果試探到最后一行,所有皇后擺放完畢,則直接打印出 8*8 的棋盤犹褒。最后一定要記得將棋盤恢復(fù)原樣,避免影響下一次擺放弛针。

實戰(zhàn)部分

組合總數(shù)Ⅱ問題:

在這里插入圖片描述

解題思路:
這道題的思路是:以 target 為根結(jié)點叠骑,依次減去數(shù)組中的數(shù)字,直到小于0或者等于0削茁,把等于0的結(jié)果記錄到結(jié)果集中宙枷。
“解集不能包含重復(fù)的組合”,就提示我們得對數(shù)組先排個序(“升序”或者“降序”均可茧跋,下面示例中均使用“升序”)慰丛。
“candidates 中的每個數(shù)字在每個組合中只能使用一次”,那就按照順序依次減去數(shù)組中的元素瘾杭,遞歸求解即可:遇到0就結(jié)算且回溯诅病,遇到負數(shù)也回溯。
candidates 中的數(shù)字可以重復(fù)粥烁,可以借助「LeetCode」第 47 題:“全排列 II”(后面刷題練習(xí)部分有鏈接) 的思想贤笆,在搜索的過程中,找到可能發(fā)生重復(fù)結(jié)果的分支讨阻,把它剪去芥永。

這里借用Leetcode上一位大佬的圖片來幫助理解

這里借用Leetcode上一位大佬的圖片來幫助理解

下面附上Python3的題解代碼

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        l=len(candidates)
        if l==0:
            return []
        candidates.sort()                                           #初始化
        path=[]
        res=[]
        
        def backtrack(begin,path,target):
            if target==0:                                           #回溯出口
                res.append(path[:])
            for i in range(begin,l):                                #回溯主體
                target_next=target-candidates[i]    #剪枝操作
                if target_next<0:
                    break
                if i>begin and candidates[i-1]==candidates[i]:
                    continue
                path.append(candidates[i])
                backtrack(i+1,path,target_next)
                path.pop()                                          #狀態(tài)返回
        
        backtrack(0,path,target)
        return res

趁熱打鐵 刷題練習(xí)部分(持續(xù)更新)

以下是LeetCode題庫中一些用到回溯算法的經(jīng)典例題的題目及解析,有題干钝吮,有題解代碼埋涧、有解題思路(持續(xù)更新):

No.17.電話號碼的字母組合:
https://blog.csdn.net/LanXiu_/article/details/104085787

No.22.括號生成:
https://blog.csdn.net/LanXiu_/article/details/104103922

No.37.解數(shù)獨:
https://blog.csdn.net/LanXiu_/article/details/104176266

No.39.組合總和:
https://blog.csdn.net/LanXiu_/article/details/104176266

No.40.組合總和Ⅱ:
https://blog.csdn.net/LanXiu_/article/details/104176266

No.44.通配符匹配:
https://blog.csdn.net/LanXiu_/article/details/104177349

No.46.全排列:
https://blog.csdn.net/LanXiu_/article/details/104177432

No.47.全排列Ⅱ:
https://blog.csdn.net/LanXiu_/article/details/104177432

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奇瘦,隨后出現(xiàn)的幾起案子棘催,更是在濱河造成了極大的恐慌,老刑警劉巖链患,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巧鸭,死亡現(xiàn)場離奇詭異,居然都是意外死亡麻捻,警方通過查閱死者的電腦和手機纲仍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贸毕,“玉大人郑叠,你說我怎么就攤上這事∶鞴鳎” “怎么了乡革?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我沸版,道長嘁傀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任视粮,我火速辦了婚禮细办,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蕾殴。我一直安慰自己笑撞,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布钓觉。 她就那樣靜靜地躺著茴肥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荡灾。 梳的紋絲不亂的頭發(fā)上瓤狐,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音卧晓,去河邊找鬼芬首。 笑死,一個胖子當著我的面吹牛逼裆,可吹牛的內(nèi)容都是我干的郁稍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胜宇,長吁一口氣:“原來是場噩夢啊……” “哼耀怜!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起桐愉,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤财破,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后从诲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體左痢,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年系洛,在試婚紗的時候發(fā)現(xiàn)自己被綠了俊性。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡描扯,死狀恐怖定页,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绽诚,我是刑警寧澤典徊,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布杭煎,位于F島的核電站,受9級特大地震影響卒落,放射性物質(zhì)發(fā)生泄漏羡铲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一导绷、第九天 我趴在偏房一處隱蔽的房頂上張望犀勒。 院中可真熱鬧,春花似錦妥曲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至押桃,卻和暖如春葵萎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唱凯。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工羡忘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人磕昼。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓卷雕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親票从。 傳聞我的和親對象是個殘疾皇子漫雕,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容