回溯法-獲取path set躏吊,一般采用樹(shù)結(jié)構(gòu)解題

????回溯實(shí)際上就是遍歷的變種,不符合條件時(shí)帐萎,本次遍歷向上回退比伏。一般來(lái)說(shuō),回溯算法都可以將決策路徑畫(huà)成樹(shù)的形狀疆导,成為一棵搜索樹(shù)赁项。回溯法執(zhí)行的過(guò)程實(shí)際上就是在這棵樹(shù)上做遍歷澈段。使用回溯法的題目悠菜,為什么不能用遞歸法,因?yàn)榛厮莘ㄖ杏涗浡窂降臈V挥幸粋€(gè)败富。

1悔醋、回溯算法的基本思想

????回溯算法的定義:回溯法采用試錯(cuò)的思想,當(dāng)它通過(guò)嘗試發(fā)現(xiàn)現(xiàn)有的分步答案不能得到有效的正確的解答的時(shí)候兽叮,它將取消上一步甚至是上幾步的計(jì)算篙顺,再通過(guò)其它的可能的分步解答再次嘗試尋找問(wèn)題的答案〕湓瘢—— 回溯法 - 維基百科[3]

????從字面意思上來(lái)看德玫,回溯(backtracking) 實(shí)際上就是“撤回一步”的意思。而在二叉樹(shù)的 DFS 遍歷中椎麦,從一個(gè)結(jié)點(diǎn)退出就是一種回溯宰僧。回溯法和 DFS 是息息相關(guān)的观挎。

????根據(jù)回溯操作的特性琴儿,我們使用棧記錄遍歷時(shí)的當(dāng)前路徑。當(dāng)進(jìn)入一個(gè)結(jié)點(diǎn)時(shí)嘁捷,做 push 操作造成;當(dāng)退出一個(gè)結(jié)點(diǎn)時(shí),做 pop 操作雄嚣,進(jìn)行回溯晒屎。

2喘蟆、案例1

????給定一個(gè)二叉樹(shù)和一個(gè)目標(biāo)和,找到所有從根結(jié)點(diǎn)到葉結(jié)點(diǎn)的路徑鼓鲁,使得路徑上所有結(jié)點(diǎn)值相加等于目標(biāo)和蕴轨。

public List<List<Integer>> pathSum(TreeNode root, int sum) {

? ? List<List<Integer>> res = new ArrayList<>();

? ? Deque<Integer> path = new ArrayDeque<>();

? ? traverse(root, sum, path, res);

? ? return res;

}

void traverse(TreeNode root, int sum, Deque<Integer> path, List<List<Integer>> res) {

? ? if (root == null) {

? ? ? ? return;

? ? }

? ? path.addLast(root.val);

? ? if (root.left == null && root.right == null) {

? ? ? ? if (root.val == sum) {

? ? ? ? ? ? res.add(new ArrayList<>(path));

? ? ? ? }

? ? }

? ? int target = sum - root.val;

? ? traverse(root.left, target, path, res);

? ? traverse(root.right, target, path, res);

? ? path.removeLast();

}

????代碼的整體結(jié)構(gòu)和上期例題題解類(lèi)似,只是加上了棧 path 記錄當(dāng)前路徑骇吭。關(guān)于棧的 push 和 pop 操作橙弱,有兩個(gè)需要注意的地方:

????????????* 保證剛進(jìn)入結(jié)點(diǎn)就 push,最后退出結(jié)點(diǎn)之前才 pop燥狰,這樣才能使當(dāng)前路徑和遍歷的進(jìn)度對(duì)應(yīng)棘脐;

????????????* 在葉結(jié)點(diǎn)判斷后,不能進(jìn)行 return龙致,否則會(huì)跳過(guò)后面的 pop 操作而出錯(cuò)蛀缝。

????這兩點(diǎn)都需要做題來(lái)體驗(yàn),建議親自做一遍例題來(lái)體會(huì)净当。

3内斯、案例2

? ? 題目:給定一組不含重復(fù)元素的整數(shù)數(shù)組 nums蕴潦,返回該數(shù)組所有可能的子集(冪集)像啼。

????Subsets 問(wèn)題就是要枚舉出集合的所有子集。生成子集有一個(gè)很簡(jiǎn)單的策略潭苞,一個(gè)子集可以選擇使用或不使用第一個(gè)元素忽冻,選好之后,再對(duì)第二個(gè)元素進(jìn)行選擇此疹,以此類(lèi)推僧诚。這就是一種回溯的思想。這又是一個(gè)樹(shù)的結(jié)構(gòu)蝗碎。一般來(lái)說(shuō)湖笨,回溯算法都可以將決策路徑畫(huà)成樹(shù)的形狀,成為一棵搜索樹(shù)蹦骑〈仁。回溯法執(zhí)行的過(guò)程實(shí)際上就是在這棵樹(shù)上做遍歷。剛好這還是一棵二叉樹(shù)眠菇,這又聯(lián)系上了二叉樹(shù)的遍歷边败。

????那么,我們可以嘗試用遍歷樹(shù)的思路寫(xiě)出回溯法的代碼捎废。這里的棧是當(dāng)前子集里的元素笑窜,push 操作是往子集里加元素,pop 操作是從子集中刪除元素(撤銷(xiāo)選擇)登疗。

????最終我們得到完整的代碼:

public List<List<Integer>> subsets(int[] nums) {

? ? Deque<Integer> current = new ArrayDeque<>(nums.length);

? ? List<List<Integer>> res = new ArrayList<>();

? ? backtrack(nums, 0, current, res);

? ? return res;

}

void backtrack(int[] nums, int k, Deque<Integer> current, List<List<Integer>> res) {

? ? if (k == nums.length) {

? ? ? ? res.add(new ArrayList<>(current));

? ? ? ? return;

? ? }

? ? // 不選擇第 k 個(gè)元素

? ? backtrack(nums, k+1, current, res);

? ? // 選擇第 k 個(gè)元素

? ? current.addLast(nums[k]);

? ? backtrack(nums, k+1, current, res);

? ? current.removeLast();

}

????這份代碼看起來(lái)和 Path Sum II 的代碼非常類(lèi)似排截,例如都使用了一個(gè)棧,遞歸的參數(shù)也很像。但是遞歸調(diào)用和 push/pop 的操作方式有一些微妙的地方匾寝。

????現(xiàn)在搬葬,我們是在調(diào)用遞歸函數(shù)之前和之后進(jìn)行 push/pop,這是因?yàn)閿?shù)組本身并沒(méi)有遞歸結(jié)構(gòu)艳悔,我們需要用 push/pop 操作來(lái)營(yíng)造出不同的選擇急凰。兩個(gè)遞歸函數(shù)的調(diào)用其實(shí)都是一樣的,但因?yàn)?current 中的內(nèi)容不一樣猜年,所以其實(shí)是兩個(gè)決策路徑抡锈。

4、時(shí)間復(fù)雜度

????回溯算法的復(fù)雜度一般都會(huì)很高乔外。以 Subsets 問(wèn)題為例床三,從搜索樹(shù)的規(guī)模可以看出算法的時(shí)間復(fù)雜度是非常高的 杨幼。不過(guò)撇簿,回溯法寫(xiě)成這樣的復(fù)雜度是可接受的,一般的回溯法題目也沒(méi)有更高效的解法差购。

5四瘫、總結(jié)

????通過(guò)這兩個(gè)例題我們看到了回溯算法和二叉樹(shù)遍歷的相似關(guān)系。在求解回溯算法的時(shí)候欲逃,我們可以先構(gòu)造一個(gè)搜索樹(shù)找蜜,在這個(gè)樹(shù)上遍歷進(jìn)行遞歸求解。

????需要注意的是稳析,例題 Subsets 中的搜索樹(shù)是二叉樹(shù)洗做,這只是個(gè)巧合。實(shí)際上搜索樹(shù)完全可以是多叉樹(shù)彰居,而且多叉樹(shù)才更常見(jiàn)诚纸。

????本篇講解的是比較基礎(chǔ)的回溯法思想〕露瑁回溯法還有很多技巧畦徘,例如 Permutation 和 Combination 系列題目,后續(xù)還會(huì)有文章進(jìn)行講解奴潘。

6旧烧、相關(guān)題目

????二叉樹(shù)遍歷的題目(理解遍歷思想):

????????????* 129 - Sum Root to Leaf Numbers[4]

????????????* 257 - Binary Tree Paths[5]

????回溯法題目(這里只列出比較簡(jiǎn)單的兩道,更多的題目可以在 LeetCode 上尋找 backtracking 標(biāo)簽):

????????????* 22 - Generate Parentheses[6]

????????????* 39 - Combination Sum[7]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末画髓,一起剝皮案震驚了整個(gè)濱河市掘剪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奈虾,老刑警劉巖夺谁,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件廉赔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡匾鸥,警方通過(guò)查閱死者的電腦和手機(jī)蜡塌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)勿负,“玉大人馏艾,你說(shuō)我怎么就攤上這事∨洌” “怎么了琅摩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵锭硼,是天一觀的道長(zhǎng)房资。 經(jīng)常有香客問(wèn)我,道長(zhǎng)檀头,這世上最難降的妖魔是什么轰异? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮暑始,結(jié)果婚禮上搭独,老公的妹妹穿的比我還像新娘。我一直安慰自己蒋荚,他們只是感情好戳稽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布馆蠕。 她就那樣靜靜地躺著期升,像睡著了一般。 火紅的嫁衣襯著肌膚如雪互躬。 梳的紋絲不亂的頭發(fā)上播赁,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音吼渡,去河邊找鬼容为。 笑死,一個(gè)胖子當(dāng)著我的面吹牛寺酪,可吹牛的內(nèi)容都是我干的坎背。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寄雀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼得滤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起盒犹,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤懂更,失蹤者是張志新(化名)和其女友劉穎眨业,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體沮协,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡龄捡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慷暂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聘殖。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖行瑞,靈堂內(nèi)的尸體忽然破棺而出就斤,到底是詐尸還是另有隱情,我是刑警寧澤蘑辑,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布洋机,位于F島的核電站,受9級(jí)特大地震影響洋魂,放射性物質(zhì)發(fā)生泄漏绷旗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一副砍、第九天 我趴在偏房一處隱蔽的房頂上張望衔肢。 院中可真熱鬧,春花似錦豁翎、人聲如沸角骤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)邦尊。三九已至,卻和暖如春优烧,著一層夾襖步出監(jiān)牢的瞬間蝉揍,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工畦娄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留又沾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓熙卡,卻偏偏與公主長(zhǎng)得像杖刷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子驳癌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

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

  • 單例定義:保證一個(gè)類(lèi)僅有一個(gè)實(shí)例滑燃,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。餓漢模式public class Singleto...
    小楊不想努力了閱讀 363評(píng)論 0 4
  • 回溯backtracking 回溯法思路的簡(jiǎn)單描述是:把問(wèn)題的解空間轉(zhuǎn)化成了圖或者樹(shù)的結(jié)構(gòu)表示喂柒,然后使用深度優(yōu)先搜...
    sylvainwang閱讀 2,246評(píng)論 0 51
  • Remove time complexity: remove from a set is O(1), remove...
    云端漫步_b5aa閱讀 622評(píng)論 0 0
  • 似乎不瓶,禾嫉,,蚊丐,返回結(jié)果的空間不會(huì)算在空間復(fù)雜度上 思維的全面性(各種邊界條件) 索引與中點(diǎn)的關(guān)系:設(shè)最后元素的索引為...
    大海一滴寫(xiě)字的地方閱讀 515評(píng)論 1 0
  • day4 33.二叉搜索樹(shù)的后序遍歷序列 思路:運(yùn)用遞歸熙参,不斷判斷左右子樹(shù)的后序遍歷序列(最后一個(gè)數(shù)字是根節(jié)點(diǎn),前...
    IAmKepler閱讀 231評(píng)論 0 0