leetcode 遞迴 回溯問題 總結

2021-10-25 02:30:49 字數 3058 閱讀 1319

注意:

整體思路清晰,回溯的過程大概是怎樣的

每層遞迴實際上要解決的問題是什麼

一定記住,該重置的狀態要重置,因為回溯就是相當於在每一層的遞迴中做選擇,選擇了不同的選項,在遇到阻礙或者達到條件結束遞迴之後,再想嘗試其他的選擇路徑,應當記住回退到之前的狀態。

縱向:遞迴的深度,完整地解決問題(搜尋完所有的方案/找到最優方案 )所必須完成地一整個連續過程,該過程的長度。例如,在「選/不選」遞迴(0/1遞迴)中,遞迴的深度是可選值的數量。

對於縱向思維,要有層層深入,逐漸解決問題的概念。對於橫向思維,其實就是從並列的多個選項中選擇乙個出來加入當前的方案,或者說是在岔路口選擇一條路.... 它只是考慮在當前的路口(某層的遞迴狀態中)解決了當前的問題。而不管可選項再多,只能從中選擇乙個,對於整個遞迴路徑來說,也只是解決了當前的乙個問題而已。

橫向:每一層遞迴考慮的選擇範圍,有多個選項,並且只能從這多個並列選項中選擇一條。例如: 「選/不選」遞迴(0/1遞迴);在網格中尋找路徑的題目中,每一層的遞迴可以考慮的選擇範圍是「上下左右」四個方向。

小結:把回溯問題當做是闖關遊戲,縱向就是遊戲進度在不斷的前進,而橫向就是每一關中自己做的不同選擇,做了不同的選擇就會走在不同的闖關路徑上,我們要不就是(1)在目前的闖關路徑上一闖到底(完成一次合格的搜尋,如果是最優問題,可能已經找到了解;如果是要給出所有可能的解,我們在記錄了合格解後,還需要回溯重置,再選擇不同的路徑重新探索)(2)要不就是領盒飯(因為一些限制條件,提前終止),然後回溯重置,再選擇不同的路徑重新探索。

人生,卻不能像回溯一樣,回退重選。在某個狀態下即使面臨很多選擇,我們也只能從中選擇乙個,然後繼續往前走,關於限制條件,它本身不能讓我們強制領盒飯,不過卻可以改變甚至重塑我們的生活和精神狀態。

而因為我們的時間線是永遠乙個方向延申的,實際上我們永遠都是在縱向路徑上前進,且還是時間有限的路徑上。

想要擁有更加豐富的人生體驗,也只有在路上多增設一些路口了,把那些沒有嘗試的橫向選項收納進來,emm......是這樣吧

如何控制遍歷每乙個可選值呢?

遞迴深度 對應於 可選值的遍歷

也就是,在每層遞迴裡我們做的就是:

77 組合

/**

* 77. 組合

給定兩個整數 n 和 k,返回 1 ... n 中所有可能的 k 個數的組合。

示例:輸入: n = 4, k = 2

輸出:[

[2,4],

[3,4],

[2,3],

[1,2],

[1,3],

[1,4],

] */

// 使用回溯,可以有兩種思路

// 1. 思路一:對於每乙個數選/不選(0/1)往深層遞迴,

// 最長的遞迴深度等於n(即最開始有哪些數可以選擇),

// 在遞迴的過程中如果遇到滿足解的要求(path的長度等於k),

// 則將合法解加入res解集(即記錄合法解)。

class solution

public void dfs(int cur, int n, int k)

//沒有可選,結束遞迴

if(cur == n + 1)

return;

//選擇當前數

path.add(cur);

dfs(cur + 1, n, k);

//回溯,重置狀態

path.remove(path.size() - 1);

//不選擇當前數,進行遞迴

dfs(cur + 1, n, k);

}}// 2. 思路二:遞迴深度是k,在每一層遞迴中從可以選擇的數的集合中選擇乙個數

// 在遞迴的過程中如果遇到滿足解的要求(path的長度等於k),

// 則將合法解加入res解集(即記錄合法解)。

class solution

void dfs(int n, int k, int cur)

for(int i = cur; i < n + 1; i++)

}}

78 子集

/***

78. 子集

給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集(冪集)。

說明:解集不能包含重複的子集。

示例:輸入: nums = [1,2,3]

輸出:[

[3],

[1],

[2],

[1,2,3],

[1,3],

[2,3],

[1,2], ]

*/// 有兩種回溯思路:

// 思路1:

class solution

// 明確每一層遞迴函式裡面解決的是:

// nums陣列中每乙個可選值,選/不選---->

// 所以遞迴結束的條件就清楚了,

// 在沒有其他的要求的情況下(77中有k的限制,可以提前終止),

// 結束遞迴就是nums中所有的可選值都被考慮過,即cur==nums.length

public void dfs(int nums, int cur)

path.add(nums[cur]);

dfs(nums, cur + 1);

path.remove(path.size() - 1);

dfs(nums, cur + 1);

}}// 思路2:

class solution

void dfs(int nums, int cur)

}}

90 子集ii

46 全排列

class solution 

void dfs(int nums, int cur)

for(int i = cur; i < nums.length; i++)

}void swap(int nums, int cur, int i)

}

47 全排列ii

Leetcode 遞迴 回溯

又稱試探法,即走不通就退回再走 當探索到某一步走不動時,發現原先選擇達不到目標,就退回一步重新選擇.用棧是否可以?數字 n 代表生成括號的對數,請你設計乙個函式,用於能夠生成所有可能的並且 有效的 括號組合。示例 1 輸入 n 3 輸出 示例 2 輸入 n 1 輸出 1 n 8 class solu...

遞迴 回溯 裝載問題

之前討論了最優裝載問題的貪心演算法,這裡討論最優裝載問題的乙個變形。1 問題描述 有一批共n個貨櫃要裝上兩艘載重量分別為c1和c2的輪船,其中貨櫃為wi,且 要求確是否有乙個合理的裝載方案可將這n個貨櫃裝上這2艘輪船?如果有,找出一種裝載方案。例如,當n 3,c1 c2 50,且w 10,40,40...

Leetcode分類 遞迴 回溯 分治

回溯是一種應用遞迴演算法,遞迴不是 題目迴圈的困難之處在於不好模擬選不選某乙個數的過程,即選了乙個數,不方便回溯到不選這個數的情況。給定一組不含重複元素的整數陣列 nums,返回該陣列所有可能的子集 冪集 說明 解集不能包含重複的子集。示例 輸入 nums 1 2,3 輸出 3 1 2 1,2,3 ...