diff --git a/problems/0077.组合.md b/problems/0077.组合.md index dabd2e8c..854b302b 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -34,7 +34,7 @@ # 思路 -本题这是回溯法的经典题目。 +本题是回溯法的经典题目。 直接的解法当然是使用for循环,例如示例中k为2,很容易想到 用两个for循环,这样就可以输出 和示例中一样的结果。 @@ -82,13 +82,13 @@ for (int i = 1; i <= n; i++) { 如果脑洞模拟回溯搜索的过程,绝对可以让人窒息,所以需要抽象图形结构来进一步理解。 -**我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中说道回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。 +**我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中说到回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。 那么我把组合问题抽象为如下树形结构: ![77.组合](https://img-blog.csdnimg.cn/20201123195223940.png) -可以看出这个棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不在重复取。 +可以看出这棵树,一开始集合是 1,2,3,4, 从左向右取数,取过的数,不再重复取。 第一次取1,集合变为2,3,4 ,因为k为2,我们只需要再取一个数就可以了,分别取2,3,4,得到集合[1,2] [1,3] [1,4],以此类推。 @@ -120,7 +120,7 @@ vector path; // 用来存放符合条件结果 其实不定义这两个全局变量也是可以的,把这两个变量放进递归函数的参数里,但函数里参数太多影响可读性,所以我定义全局变量了。 -函数里一定有两个参数,既然是集合n里面取k的数,那么n和k是两个int型的参数。 +函数里一定有两个参数,既然是集合n里面取k个数,那么n和k是两个int型的参数。 然后还需要一个参数,为int型变量startIndex,这个参数用来记录本层递归的中,集合从哪里开始遍历(集合就是[1,...,n] )。 @@ -389,9 +389,8 @@ class Solution(object): # 剪枝, 最后k - len(path)个节点直接构造结果,无需递归 last_startidx = n - (k - len(path)) + 1 - result.append(path + [idx for idx in range(last_startidx, n + 1)]) - for x in range(startidx, last_startidx): + for x in range(startidx, last_startidx + 1): path.append(x) backtracking(n, k, x + 1) # 递归 path.pop() # 回溯 @@ -435,6 +434,36 @@ class Solution: return res ``` +### Go +```Go +var ( + path []int + res [][]int +) + +func combine(n int, k int) [][]int { + path, res = make([]int, 0, k), make([][]int, 0) + dfs(n, k, 1) + return res +} + +func dfs(n int, k int, start int) { + if len(path) == k { // 说明已经满足了k个数的要求 + tmp := make([]int, k) + copy(tmp, path) + res = append(res, tmp) + return + } + for i := start; i <= n; i++ { // 从start开始,不往回走,避免出现重复组合 + if n - i + 1 < k - len(path) { // 剪枝 + break + } + path = append(path, i) + dfs(n, k, i+1) + path = path[:len(path)-1] + } +} +``` ### javascript @@ -481,63 +510,6 @@ function combine(n: number, k: number): number[][] { }; ``` - - -### Go -```Go -var res [][]int -func combine(n int, k int) [][]int { - res=[][]int{} - if n <= 0 || k <= 0 || k > n { - return res - } - backtrack(n, k, 1, []int{}) - return res -} -func backtrack(n,k,start int,track []int){ - if len(track)==k{ - temp:=make([]int,k) - copy(temp,track) - res=append(res,temp) - } - if len(track)+n-start+1 < k { - return - } - for i:=start;i<=n;i++{ - track=append(track,i) - backtrack(n,k,i+1,track) - track=track[:len(track)-1] - } -} -``` -剪枝: -```Go -var res [][]int -func combine(n int, k int) [][]int { - res=[][]int{} - if n <= 0 || k <= 0 || k > n { - return res - } - backtrack(n, k, 1, []int{}) - return res -} -func backtrack(n,k,start int,track []int){ - if len(track)==k{ - temp:=make([]int,k) - copy(temp,track) - res=append(res,temp) - } - if len(track)+n-start+1 < k { - return - } - for i:=start;i<=n;i++{ - track=append(track,i) - backtrack(n,k,i+1,track) - track=track[:len(track)-1] - } -} -``` - ### Rust ```Rust