LeetCode 216. 组合总和 III

137 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第44天,点击查看活动详情.

216. 组合总和 III

题目描述

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

  • 只使用数字1到9

  • 每个数字 最多使用一次

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
在这里插入图片描述

解题思路

思路一: 回溯

对于这类寻找所有可行解的题,我们都可以尝试用搜索回溯的方法来解决。

【回溯问题解体步骤】
判断当前情况是否非法,如果非法就立即返回;
当前情况是否已经满足递归结束条件,如果是就将当前结果保存起来并返回;
当前情况下,遍历所有可能出现的情况并进行下一步的尝试;
递归完毕后,立即回溯,回溯的方法就是取消前一步进行的尝试

回溯解题框架如下:

res = [];
backtrace(路径, 选择列表)  {
    if (满足条件) {
        res.push(路径)
        return
    }
    for (选择 in 选择列表) {
        做选择
        backtrace(路径, 选择列表)
        撤销选择
    }
}

套用模板就行。

实现代码如下:

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
    let res = [];
    backtrace(1, k, [], n, res);
    return res;
}; 

function backtrace(begin, k, path, target, res) {
    // 结束条件
    if (target == 0 && path.length == k) {
        res.push([...path]);
        return;
    }

    // 选择列表
    for (let i = begin; i < 10; i++) {
        // 大剪枝
        if (target - i < 0) return;
        // 选择
        path.push(i);
        // 递归 i + 1, target - i
        backtrace(i + 1, k, path, target - i, res);
        // 回溯 撤销选择 
        path.pop();
    }
}

思路二: 组合枚举

  1. tmp 数组存放已经被选出的数字
  2. 定义dfs(curr, n, k, sum, res)函数 , curr从1开始, 在整个递归调用的过程中,curr 是从小到大递增的, 对于curr, 我们可以选择取或者不取

剪枝情况: tmp 长度加上区间 [cur, n] 的长度小于 k 或者tmp数组长度大于k
当tmp数组长度等于k并且和等于n, 即把结果加入结果集中并返回;

实现代码如下:

/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
    let tmp = [],
        res = [];

    const dfs = (curr, n, k, sum, res) => {
        // 剪枝:tmp 长度加上区间 [cur, n] 的长度小于 k,不可能构造出长度为 k 的 tmp
        if (tmp.length + (n - curr + 1) < k || tmp.length > k) {
            return;
        }        
        if (tmp.length === k && tmp.reduce((prev, next) => prev + next, 0) === sum) {
            res.push([...tmp]);
            return;
        }
        tmp.push(curr);
        // 考虑选择当前位置
        dfs(curr + 1, n, k, sum, res);
        tmp.pop();
        // 不选择当前位置
        dfs(curr + 1, n, k, sum, res);
    }

    dfs(1, 9, k, n, res);
    return res;
};

参考资料

回溯解决组合问题 - 组合总和 III - 力扣(LeetCode)

组合 - 组合 - 力扣(LeetCode)