文巾解题 77. 组合
1 題目描述
2? 解題思路?
- 如果解決一個問題有多個步驟,每一個步驟有多種方法,題目又要我們找出所有的方法,可以使用回溯算法;
- 回溯算法是在一棵樹上的?深度優先遍歷(因為要找所有的解,所以需要遍歷);
- 組合問題,相對于排列問題而言,不計較一個組合內元素的順序性(即 [1, 2, 3] 與 [1, 3, 2] 認為是同一個組合),因此很多時候需要按某種順序展開搜索,這樣才能做到不重不漏。
既然是樹形問題上的 深度優先遍歷,因此首先畫出樹形結構。
例如輸入:n = 4, k = 2,我們可以發現如下遞歸結構:
如果組合里有 1 ,那么需要在 [2, 3, 4] 里再找 1個數;
如果組合里有 2 ,那么需要在 [3, 4] 里再找 1數。注意:這里不能再考慮 1,因為包含 1?的組合,在第 1 種情況中已經包含。
依次類推(后面部分省略),以上描述體現的 遞歸 結構是:在以 n?結尾的候選數組里,選出若干個元素。畫出遞歸結構如下圖:
參考:https://leetcode-cn.com/problems/combinations/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-ma-/
2.1? 未剪枝回溯
class Solution:def combine(self, n: int, k: int) -> List[List[int]]:res = []def backtrace(i,tmp):if len(tmp) == k:res.append(tmp)returnfor j in range(i,n+1):backtrace(j+1,tmp+[j])backtrace(1,[])return res這里backtrace(i,lst)的意思是:在[1,i)里面,我們已經找到了一個排序lst(最后一個數就是i-1)。然后我們在[i,n]里面找一個點,作為排序的下一個點。
當我們lst的長度已經是k的時候,滿足條件,就可以將這個序列放入我們要返回的部分了
這樣查找是不會有重復的序列的。
2.2 剪枝回溯
但是,上述方法會有很多地方存在冗余,當我們剩余沒有查看的序列的長度比我們還需要取得元素個數要少的時候,那么即使后面整個序列中的元素全部取出來,也不能達到條件。那么這一部分的backtrace就可以不用考慮了。
剪枝后的代碼如下:
class Solution:def combine(self, n: int, k: int) -> List[List[int]]:res = []def backtrace(i,tmp):if len(tmp) == k:res.append(tmp)returnfor j in range(i,n+1):if(len(tmp)+n-j+1<k):returnbacktrace(j+1,tmp+[j])backtrace(1,[])return res多了一句if(len(tmp)+n-j+1<k):,就是來判斷剩余序列的長度是否滿足要求的
可以看到,時間復雜度小了很多
2.3 寫代碼的時候的一個小坑
一開始我是這么寫的,然后報錯了
class Solution:def combine(self, n: int, k: int) -> List[List[int]]:tmp=[]ans=[]def dfs(idx):if(len(tmp)+(n-idx+1)<k):returnif(len(tmp)==k):ans.append(tmp)returntmp.append(idx)dfs(idx+1)tmp.pop()dfs(idx+1)dfs(1)return(ans)?從邏輯上看,也沒有問題,但是注意一點,就是append(tmp) append的是一個引用,所以append里面的值會是一樣的。
?
稍微修改一下,就對了
class Solution:def combine(self, n: int, k: int) -> List[List[int]]:ans=[]def dfs(idx,tmp):if(len(tmp)+(n-idx+1)<k):returnif(len(tmp)==k):ans.append(tmp)returndfs(idx+1,tmp)tmp1=tmp+[idx]dfs(idx+1,tmp1)dfs(1,[])return(ans)總結
以上是生活随笔為你收集整理的文巾解题 77. 组合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文笔记目录
- 下一篇: 文巾解题 46. 全排列