天天看点

LeetCode - 40 组合总和 II

目录

题目来源

题目描述

示例

提示

题目解析

算法源码

题目来源

40. 组合总和 II - 力扣(LeetCode)

题目描述

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。 

示例

输入: candidates = [10,1,2,7,6,1,5], target = 8,

输出: [ [1,1,6], [1,2,5], [1,7], [2,6] ]

输入: candidates = [2,5,2,1,2], target = 5,

输出: [ [1,2,2], [5] ]

提示

  • 1 <= candidates.length <= 100

  • 1 <= candidates[i] <= 50

  • 1 <= target <= 30

题目解析

本题的难点在于,输入数组中存储值重复的元素,这样必然会产生重复的组合,但是题目要求结果中不能存在重复的组合。

比如 candidates = [1,1,2], target = 3,则存在如下组合

LeetCode - 40 组合总和 II

可以发现有两个重复的12组合。

此时避免重复有两种做法,一种是从根源去重,即对candidates去重,但是去重前需要统计重复值的次数

LeetCode - 40 组合总和 II

另一种去重策略是,广度for循环遍历时,检查candidate[i]是否和candidate[i-1]相同,若相同,则candidate[i]可以提前结束,不需要进入递归流程,因为这样只会产生重复的组合

LeetCode - 40 组合总和 II

算法源码

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
const result = []
var combinationSum2 = function(candidates, target) {
    result.length = 0

    let count = {}
    candidates.forEach(ele => {
        count[ele] ? count[ele]++ : (count[ele] = 1)
    })

    dfs([...new Set(candidates)].sort((a,b)=>a-b), count, target, 0, [])
    return result
};

function dfs(candidates, count, target, index, path) {
    if(target <= 0) {
        if(target === 0) result.push([...path])
        return
    }

    for(let i=index; i<candidates.length; i++) {
        if(candidates[i] > target) break;

        if(count[candidates[i]] > 0) {
            path.push(candidates[i])
            count[candidates[i]]--
            dfs(candidates, count, target - candidates[i], i, path)
            count[candidates[i]]++
            path.pop()
        }
    }
}
           
LeetCode - 40 组合总和 II
/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */

var combinationSum2 = function(candidates, target) {
    candidates.sort((a,b) => a - b)

    const res = []
    dfs(candidates, target, 0, 0, [],  res)
    return res
};

function dfs(candidates, target, index, sum, path, res) {
    if(sum > target) return
    if(sum === target) return res.push([...path])

    for(let i=index; i<candidates.length; i++) {
        if(i > 0 && candidates[i] === candidates[i-1]) continue
        path.push(candidates[i])
        dfs(candidates, target, i+1, sum + candidates[i], path, res)
        path.pop()
    }
}
           
LeetCode - 40 组合总和 II