448,組合的幾種解決方式

2021-10-09 11:51:58 字數 2666 閱讀 9971

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

示例:

輸入: n = 4, k = 2

輸出:

[[2,4],

[3,4],

[2,3],

[1,2],

[1,3],

[1,4],

]

回溯方式解決這題要求的是從n個數字中選出k個弄成一組合,問最後總共有多少種組合,其實我們可以把它看做是一棵n-k+1叉樹,比如n=4,k=2,那麼就是一顆3叉樹,這裡以示例為例畫個圖看一下。

注意這裡只能選擇後面的數字不能選擇前面的數字,比如我選擇了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 多...