【LeetCode】77. 组合

leetcode

 

算法思路

核心采用回溯法(DFS)遍历所有可能的组合,并通过剪枝减少无效搜索。关键点在于:

  1. ​升序选择​​:保证组合内元素按升序排列,避免重复(如 [1,2] 和 [2,1] 视为同一组合)
  2. ​剪枝优化​​:剩余待选元素数量必须 ≥ 剩余需要选择的元素数量,否则提前终止分支

实现代码

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
}

代码解析

  1. ​核心逻辑​​:backtrack 函数通过递归实现深度优先搜索
    • start 参数保证每次选择的数字递增
    • path 记录当前路径,到达长度 k 时存入结果集
  2. ​剪枝优化​​:maxStart 计算公式 n - (k - len(path)) + 1,确保剩余数字足够完成组合
    maxStart := n - (k - len(path)) + 1
  3. ​避免结果篡改​​:使用 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]]
}
posted @ 2025-04-04 15:27  云隙之间  阅读(32)  评论(0)    收藏  举报