LeetCode-39-组合总和
in LeetCode with 0 comment

LeetCode-39-组合总和

in LeetCode with 0 comment

原题地址:组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

回溯算法

对每个位置的数字,依次尝试不同的重复次数,判断是否能得到可用的组合。

具体的实现代码如下:

/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
const combinationSum1 = function(candidates, target) {
    candidates.sort((a, b) => a - b);

    /**
     * 求解从某一个位置开始,后面部分得到的和为sum的组合
     * @param index 开始位置
     * @param sum 要求的和
     * @returns {[]|Array} 得到的结果集
     */
    const combine = (index, sum) => {
        // 数组已处理完,不会有新的结果出现,返回空数组
        if (index === candidates.length) {
            return [];
        }
        // 因为已经排过序,如果要处理的第一个数就比要得到的sum大,显然求和后是要大于sum的
        if (candidates[index] > sum) {
            return [];
        }
        let result = [];
        for (let i = 0; i <= Math.floor(sum/candidates[index]); i ++) {
            // 得到了结果,将结果保存到result中
            if (sum === i * candidates[index]) {
                result.push(new Array(i).fill(candidates[index]));
            } else {
                // 将sum减去i次第一个数,然后递归求解后面的部分
                let array = combine(index + 1, sum - i * candidates[index]);
                // 如果后面部分有解,就进行合并
                if (array.length > 0) {
                    for (let j = 0; j < array.length; j ++) {
                        result.push(new Array(i).fill(candidates[index]).concat(array[j]));
                    }
                }
            }
        }
        return result;
    };
    // 从0开始求解
    return combine(0, target);
};

测试:

let start = new Date();
const test = combinationSum1;
console.log(test([2,3,6,7], 7)); // [ [ 7 ], [ 2, 2, 3 ] ]
console.log(test([2,3,5], 8)); // [ [ 3, 5 ], [ 2, 3, 3 ], [ 2, 2, 2, 2 ] ]
console.log(new Date().getTime() - start.getTime()); // 9