給定兩個整數 n 和 k,返回 1 … n 中所有可能的 k 個數的組合。
示例:
輸入: n = 4, k = 2回溯方式解決這題要求的是從n個數字中選出k個弄成一組合,問最後總共有多少種組合,其實我們可以把它看做是一棵n-k+1叉樹,比如n=4,k=2,那麼就是一顆3叉樹,這裡以示例為例畫個圖看一下。輸出:
[[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
注意這裡只能選擇後面的數字不能選擇前面的數字,比如我選擇了2,就能在選擇1了,否則就會出現[1,2]和[2,1]這種重複的組合,同理我選擇了3,那麼1和2都不能再選了因為如果再選就會出現重複。
n叉樹的遍歷還記得嗎
private
void
backtrack()
for(
int i =
?; i <= n - k +
1; i++
)}
我們來看下上面的框架,邏輯運算1的時候,就表示沿著當前分支走下去,我們把當前選擇的值新增到集合中。邏輯2表示這個分支走完了我們要跳到另乙個分支,之前講426,什麼是遞迴,通過這篇文章,讓你徹底搞懂遞迴的時候提到過,從乙個分支跳到另乙個分支的時候,要麼之前分支在運算之前先複製乙份,要麼把當前分支新增的值給移除,否則會造成分支汙染。這兩種方式都可以,但後一種效率會更好,他不會大量的複製資料。那麼終止條件是什麼呢,就是集合中的資料大小為k的時候,就表示找到了一組組合。搞懂了這一點**就比較容易寫了
public list
>
combine
(int n,
int k)
private
void
backtrack
(list
> list,
int n,
int k,
int start, list
templist)
//注意這裡的i不能從0開始,如果從0開始會出現重複的,比如[1,2]和[2,1]
for(
int i = start; i <= n - k +
1; i++
)}
參考二進位制位我們知道二進位制位中,每個位置有兩種狀態,一種是0一種是1,這裡也可以參照位運算的表示方式,每個數字都有選和不選兩種狀態,具體畫個圖來看下
//選擇當前值,k要減1
templist.
add(start)
;backtrack
(list, n, k -
1, start +
1, templist)
;//因為是遞迴呼叫,跳到下乙個分支的時候,要把這個分支選的值給移除
templist.
remove
(templist.
size()
-1);
}遞迴方式解決這題要求的是從n個數字中選出k個弄成一組合,問最後總共有多少種組合,如果用數學知識就是c(n,k),這個公式又可以表示為c(n,k)=c(n-1,k-1)+c(n-1,k),也就是說要麼選第n個數字,要麼不選第n個數字。
(1),選第n個數字
如果選第n個數字,我們需要從前面n-1個數字中選擇k-1個,然後在和數字n組合
(2),不選第n個數字
如果不選第n個數字,我們可以直接從前面n-1個數字中選擇k個即可
那麼最終的結果就是上面兩種的和,我們來直接看下**
public list
>
combine
(int n,
int k)
總結這題也不是特別難,但解題思路很多,每一種都比較經典。關於組合的題型也比較多,前面還講過391,回溯演算法求組合問題,有興趣的也可以看下
1317 組合的輸出
排列與組合是常用的數學方法,其中組合就是從n個元素中抽出r個元素 不分順序且r n 我們可以簡單地將n個元素理解為自然數1,2,n,從中任取r個數。現要求你用遞迴的方法輸出所有組合。例如n 5,r 3,所有組合為 1 2 3 1 2 4 1 2 5 1 3 4 1 3 5 1 4 5 2 3 4 2...
2020 10 06組合的輸出
題目描述 排列與組合是常用的數學方法,其中組合就是從nn個元素中抽出rr個元素 不分順序且r le n r n 我們可以簡單地將nn個元素理解為自然數1,2,n1,2,n,從中任取rr個數。現要求你輸出所有組合。例如n 5,r 3n 5,r 3,所有組合為 12 3 1 2 4 1 2 5 1 3 ...
20 組合索引的使用
為什麼有最左原則?例如你這個聯合索引是 state city zipcode 那麼state就是第一關 city是第二關,zipcode就是第三關 你必須匹配了第一關,才能匹配第二關,匹配了第一關和第二關,才能匹配第三關 你不能直接到第二關的 索引的格式就是第一層是state,第二層才是city 多...