LeetCode39 组合总和(带扩展)

leetcode.cn/problems/co...

解法一:回溯

这道题的关键在于 candidates 中的元素不重复,但一个元素可以复用多次,概括就是元素无重可复选 , 之前子集/组合问题(参考这篇文章),为了避免重复选,我们每次循环 ioffset 开始遍历,循环中递归下一层回溯树是从 i + 1offset + 1 开始遍历,从而保证 nums[offset] 这个元素不会被重复使用。

现在想让每个元素被重复使用,只要把 i + 1 改成 i 即可,在遍历这棵决策树的过程中,当前已经选择过的元素就可以在下一层递归被再次选择。

go 复制代码
func combinationSum(candidates []int, target int) [][]int {
    var res [][]int
    var pathSum int
    path := make([]int, 0)
    backtrack(candidates, 0, target, path, &pathSum, &res)
    return res
}

func backtrack(nums []int, offset int, target int, path []int, pathSum *int, res *[][]int) {
    if *pathSum == target{ // 找到目标和
        tmp := make([]int, len(path))
        copy(tmp, path)
        *res = append(*res, tmp)
        return
    }
    if *pathSum > target{ // 超过目标和提前结束
        return
    }
    for i:=offset; i<len(nums); i++{
        // 做选择
        path = append(path, nums[i])
        *pathSum+=nums[i]
        backtrack(nums, i, target, path, pathSum, res) // 递归起点仍在当前位置,当前元素可被下一层复选
        // 撤销选择
        path = path[:len(path)-1]
        *pathSum-=nums[i]
    }
}

扩展

来看这道题组合总和 II 题意变成元素有重不可复选 ,我们参考这篇文章扩展2中的解法,先对原数组排序,相同的元素放在相邻的位置上,然后在遍历决策树的过程中进行剪枝

go 复制代码
func combinationSum2(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    var res [][]int
    var pathSum int
    path := make([]int, 0)
    backtrack(candidates, 0, target, path, pathSum, &res)
    return res
}

func backtrack(nums []int, offset int, target int, path []int, pathSum int, res *[][]int){
    if pathSum == target{ 
        tmp := make([]int, len(path))
        copy(tmp, path)
        *res = append(*res, tmp)
        return
    }
    if pathSum > target{ // 超过目标和,直接结束
        return
    }
    for i:=offset; i<len(nums); i++{
        if i > offset && nums[i] == nums[i-1]{ // 值相同的树枝,只遍历第一条
            continue
        }
        path = append(path, nums[i])
        pathSum+=nums[i]
        backtrack(nums, i+1, target, path, pathSum, res)
        path = path[:len(path)-1]
        pathSum-=nums[i]
    }
}
相关推荐
江城开朗的豌豆39 分钟前
JavaScript篇:a==0 && a==1 居然能成立?揭秘JS中的"魔法"比较
前端·javascript·面试
江城开朗的豌豆1 小时前
JavaScript篇:setTimeout遇上for循环:为什么总是输出5?如何正确输出0-4?
前端·javascript·面试
AntBlack1 小时前
计算机视觉 : 端午无事 ,图像处理入门案例一文速通
后端·python·计算机视觉
天涯学馆1 小时前
TypeScript 在大型项目中的应用:从理论到实践的全面指南
前端·javascript·面试
穗余3 小时前
NodeJS全栈开发面试题讲解——P7 DevOps 与部署和跨域等
前端·面试·node.js
福大大架构师每日一题3 小时前
2025-06-02:最小可整除数位乘积Ⅱ。用go语言,给定一个表示正整数的字符串 num 和一个整数 t。 定义:如果一个整数的每一位都不是 0,则称该整数为
后端
汪汪汪侠客3 小时前
源码解析(一):GraphRAG
算法·面试·大模型·rag·graphrag
Code_Artist3 小时前
[Mybatis] 因 0 != null and 0 != '' 酿成的事故,害得我又过点啦!
java·后端·mybatis
程序员博博3 小时前
看到这种代码,我直接气到想打人
后端
零叹3 小时前
篇章七 数据结构——栈和队列
java·数据结构·面试·面试题·双端队列··队列