代碼隨想錄算法訓(xùn)練營打卡Day24 | 回溯法理論基礎(chǔ)復(fù)習(xí)消玄、LeetCode77 組合

摘要

  • 回溯和遞歸是相輔相成的,用到回溯的地方一般都會有遞歸丢胚。遞歸是實現(xiàn)回溯的基本方法翩瓜。
  • 回溯法并不是很高效的算法,是一種暴力枚舉法携龟,通過枚舉可能答案來解決問題兔跌。
  • 回溯法提供了一種枚舉各種可能性的方法,讓一些難以用多層循環(huán)搜索答案的問題至少能用回溯法解決峡蟋,如組合問題和切割問題坟桅。
  • 所有的回溯法的問題都可以抽象為樹形結(jié)構(gòu),即可能答案的構(gòu)造是樹形的蕊蝗。

回溯法基礎(chǔ)

相關(guān)定義和概念

  • 定義:回溯法也可以叫做回溯搜索法仅乓,是一種搜索的方式。
  • 組合:可以理解為數(shù)學(xué)上的集合蓬戚,并不強調(diào)元素的順序和相對位置夸楣。
  • 排列:可以理解為數(shù)學(xué)上的數(shù)列,強調(diào)元素的順序。

回溯法的意義

  • 回溯法的本質(zhì)是窮舉豫喧,窮舉所有可能的答案石洗,然后驗證這些答案是否符合題目要求,選出合適的答案紧显。
  • 有一些問題只能用回溯法解決讲衫,目前并沒有更高效的解法。

回溯法的理解

  • 可能答案的枚舉過程是樹形的鸟妙,可以通過畫出答案的構(gòu)造樹來幫助思考焦人。
  • 回溯法的過程都可以抽象為N叉樹挥吵。
  • 回溯法解決的問題是在給定集合中遞歸查找子集重父,集合的大小決定了答案樹的寬度(一個節(jié)點有幾個孩子),遞歸的深度構(gòu)成了答案樹的深度忽匈。
  • 遞歸用于向下找房午,循環(huán)用于在同一層中找
遞歸與循環(huán)

回溯法的模板

  • 回溯法的遞歸函數(shù)一般沒有返回值。
  • 遞歸函數(shù)一般命名為backtracking丹允。
  • 回溯法的參數(shù)列表在一開始是不好確定的郭厌,會在分析問題的過程中逐漸完善。
  • 先寫遞歸的終止條件雕蔽,在終止條件下收集結(jié)果折柠。
  • 然后寫單層搜索的邏輯,一般情況下是for循環(huán)批狐,用來處理當(dāng)前集合里的每一個元素扇售。用答案樹來看,也可以對應(yīng)處理當(dāng)前節(jié)點的每一個子節(jié)點嚣艇。
  • for循環(huán)中一般做三件事:1. 處理當(dāng)前節(jié)點承冰;2. 調(diào)用遞歸函數(shù);3. 撤銷操作(回溯)
void backtracking(arg...) {
    if (/* 終止條件 */) {
        /* 收集結(jié)果 */
        return;
    }
    for (/* 每一個集合中的元素 */) {
        /* 1. 處理當(dāng)前元素 */
        /* 2. 調(diào)用遞歸函數(shù) */
        /* 3. 撤銷處理(回溯) */
    }
    return;
}

還要繼續(xù)理解和總結(jié)食零,先多寫一些回溯法的題目困乒。


LeetCode77 組合

77. 組合 - 力扣(Leetcode)

  • 初見題目的想法:按照以上的回溯模板進行思考
    • 首先回溯法的遞歸函數(shù)不返回值
    • 遞歸函數(shù)命名為backtracking
    • 在分析問題的過程中確定參數(shù)列表
    • 先寫遞歸的終止條件:當(dāng)前組合cur的元素個數(shù)cur.size()等于k,則收集當(dāng)前組合cur贰谣,然后直接返回娜搂。(這步確定需要傳入的參數(shù)為結(jié)果集res,當(dāng)前組合cur吱抚,元素個數(shù)k
    • 再寫單層搜索的邏輯:用for循環(huán)向cur中嘗試加入元素(這步確定需要傳入的參數(shù)為n涌攻,還有防止組合重復(fù)所需的元素的起始值j
  • 按照回溯法的模板進行思考频伤,可以很容易的寫出如下代碼恳谎。我將當(dāng)前組合命名為cur,和遍歷二叉樹時對節(jié)點的命名類似,提醒自己用樹的形式去理解回溯法因痛。cur對應(yīng)的就是答案的構(gòu)造樹上的某個節(jié)點婚苹。

初見題目的題解代碼如下

class Solution {
public:
    void backtracking(vector<vector<int>>& res, int& n, int& k, vector<int> cur, int j) {
        if (cur.size() == k) {
            res.push_back(cur);
            return;
        }
        for (int i = j; i <= n; i++) {
            cur.push_back(i);
            backtracking(res, n, k, cur, i + 1);
            cur.pop_back();
        }
        return;
    } 
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> res;
        vector<int> cur;
        backtracking(res, n, k, cur, 1);
        return res;
    }
};

以上代碼的遞歸函數(shù)的參數(shù)列表里的cur沒有傳引用(vector<int> cur),多次拷貝vector鸵膏,代碼效率較差膊升。

改為傳引用vector<int>& cur,可見能顯著提升效率谭企。

class Solution {
public:
    void backtracking(vector<vector<int>>& res, int& n, int& k, vector<int> cur, int j) {
        if (cur.size() == k) {
            res.push_back(cur);
            return;
        }
        for (int i = j; i <= n; i++) {
            cur.push_back(i);
            backtracking(res, n, k, cur, i + 1);
            cur.pop_back();
        }
        return;
    } 
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> res;
        vector<int> cur;
        backtracking(res, n, k, cur, 1);
        return res;
    }
};
  • 組合問題較簡單廓译,在這里在復(fù)習(xí)一次回溯法的三步思考來總結(jié)今天的復(fù)習(xí):

    1. 在分析問題的過程中確定遞歸函數(shù)需要的參數(shù)
    2. 確定遞歸的終止條件,在終止條件里收集結(jié)果
    3. 確定單層遞歸的處理邏輯
  • 剪枝待第二天復(fù)習(xí)债查。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末非区,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子盹廷,更是在濱河造成了極大的恐慌征绸,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俄占,死亡現(xiàn)場離奇詭異管怠,居然都是意外死亡,警方通過查閱死者的電腦和手機缸榄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門渤弛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甚带,你說我怎么就攤上這事她肯。” “怎么了欲低?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵辕宏,是天一觀的道長。 經(jīng)常有香客問我砾莱,道長瑞筐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任腊瑟,我火速辦了婚禮聚假,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闰非。我一直安慰自己膘格,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布财松。 她就那樣靜靜地躺著瘪贱,像睡著了一般纱控。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菜秦,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天甜害,我揣著相機與錄音,去河邊找鬼球昨。 笑死尔店,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的主慰。 我是一名探鬼主播嚣州,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铜靶,長吁一口氣:“原來是場噩夢啊……” “哼溢陪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起河爹,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤璃谨,失蹤者是張志新(化名)和其女友劉穎沙庐,沒想到半個月后鲤妥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佳吞,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年棉安,在試婚紗的時候發(fā)現(xiàn)自己被綠了底扳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡贡耽,死狀恐怖衷模,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蒲赂,我是刑警寧澤阱冶,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站滥嘴,受9級特大地震影響木蹬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜若皱,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一镊叁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧走触,春花似錦晦譬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春像樊,著一層夾襖步出監(jiān)牢的瞬間夸溶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工凶硅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缝裁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓足绅,卻偏偏與公主長得像捷绑,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子氢妈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

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