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]
    }
}
相关推荐
235166 分钟前
【JVM】Java为啥能跨平台?JDK/JRE/JVM的关系?
java·开发语言·jvm·spring boot·后端·spring·职场和发展
courtfu17 分钟前
Plugin ‘mysql_native_password‘ is not loaded`
java·后端
ShineWinsu25 分钟前
对于数据结构:堆的超详细保姆级解析——下(堆排序以及TOP-K问题)
c语言·数据结构·c++·算法·面试·二叉树·
_Power_Y1 小时前
计算机网络面试题
面试
上进小菜猪1 小时前
测试自动化Replay:让数据库迁移测试回归真实场景的一把“利器”
后端
Python私教1 小时前
FastAPI × SQLAlchemy 2.0 Async:从“能跑”到“可压测”的完整工程实践
后端
Python私教1 小时前
FastAPI × Loguru:从“能跑”到“可运维”的日志实战
后端
Craaaayon2 小时前
如何选择两种缓存更新策略(写缓存+异步写库;写数据库+异步更新缓存)
java·数据库·redis·后端·缓存·mybatis
火山上的企鹅2 小时前
Qt C++ 软件开发工程师面试题
c++·qt·面试
bitbitDown3 小时前
从零打造一个 Vite 脚手架工具:比你想象的简单多了
前端·javascript·面试