【Leetcode】40. 组合总和 II

65 阅读1分钟

leetcode-40.png

题目简述:从给定的数组中找出若干个数字,使这些数字之和等于target,不能包含重复的组合,每个元素只能只用一次

错误代码

下面的代码无法去重

var combinationSum2 = function (candidates, target) {
    let res = []
    candidates.sort((a, b) => a - b)
    var backtrack = function (start, one, sum) {
        if (sum === 0) {
            res.push([...one])
            return
        }
        if (sum < 0) return
        for (let i = start; i < candidates.length; ++i) {
            one.push(candidates[i])
            backtrack(i + 1, one, sum - candidates[i])
            one.pop()
        }
    }
    backtrack(0, [], target)
    return res
};

无法去重的测试用例
因为存在两个 1,导致下面的这个问题

无法通过的测试用例.png

再一个就是想到了使用set来去重,但是set存数组的话,是存取的数组的引用,所以也不能使用set来去重,如果实在想使用set的话,可以使用arr.join(',')来把数组变成字符串再存到set

最终解决方案

重点就是 12 行
这里就要深刻的理解回溯了,这里就是产生的一棵树,那么for进行遍历的时候,是进行的同一层级的计算,那么就会跳过相同的元素
for 进行的是广度
for 里面的backtrack就是深度了,

var combinationSum2 = function (candidates, target) {
    let res = []
    candidates.sort((a, b) => a - b)
    var backtrack = function (start, one, sum) {
        if (sum === 0) {
            res.push([...one])
            return
        }
        if (sum < 0) return
        for (let i = start; i < candidates.length; ++i) {
            // 跳过同一层级中的形同元素, 同一层级 打重点
            if (i > start && candidates[i] === candidates[i - 1]) continue
            one.push(candidates[i])
            backtrack(i + 1, one, sum - candidates[i])
            one.pop()
        }
    }
    backtrack(0, [], target)
    return res
};