【LeetCode】77. 组合
算法思路
核心采用回溯法(DFS)遍历所有可能的组合,并通过剪枝减少无效搜索。关键点在于:
- 升序选择:保证组合内元素按升序排列,避免重复(如 [1,2] 和 [2,1] 视为同一组合)
- 剪枝优化:剩余待选元素数量必须 ≥ 剩余需要选择的元素数量,否则提前终止分支
实现代码
func combine(n int, k int) [][]int { var res [][]int var backtrack func(start int, path []int) backtrack = func(start int, path []int) { // 当路径长度等于k时,记录结果 if len(path) == k { tmp := make([]int, k) copy(tmp, path) // 复制当前路径避免后续修改 res = append(res, tmp) return } // 计算当前可选的数字范围上限(剪枝优化) // 剩余需要选的数量 = k - len(path) // 最大起始数字应满足:剩余数字数量 >= 剩余需要选的数量 → i <= n - (k - len(path)) + 1 maxStart := n - (k - len(path)) + 1 for i := start; i <= maxStart; i++ { path = append(path, i) // 选择当前数字 backtrack(i+1, path) // 递归下一层,起始位置+1避免重复 path = path[:len(path)-1] // 回溯,撤销选择 } } backtrack(1, []int{}) // 从数字1开始回溯 return res }
代码解析
- 核心逻辑:
backtrack函数通过递归实现深度优先搜索start参数保证每次选择的数字递增path记录当前路径,到达长度 k 时存入结果集
- 剪枝优化:
maxStart计算公式n - (k - len(path)) + 1,确保剩余数字足够完成组合maxStart := n - (k - len(path)) + 1
- 避免结果篡改:使用
copy创建新切片,防止后续回溯修改已存储结果tmp := make([]int, k) copy(tmp, path)
复杂度分析
- 时间复杂度:O(C(n,k) × k),其中 C(n,k) 是组合数,每个组合需要 O(k) 时间复制
- 空间复杂度:O(k) 递归栈深度,结果集不计入复杂度
测试用例验证
func main() { fmt.Println(combine(4, 2)) // 输出:[[1 2] [1 3] [1 4] [2 3] [2 4] [3 4]] fmt.Println(combine(1, 1)) // 输出:[[1]] }

浙公网安备 33010602011771号