【前端er每日算法】回溯算法-216组合三-17.电话号码组合

142 阅读1分钟

题目1 216. 组合总和 III

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

只使用数字1到9 每个数字 最多使用一次  返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

思路

和求数的全部组合基本一样,但是加了判断条件,在终点时需要判断当前的和是否符合条件,符合的话再加入结果集中。

如何进行和的收集呢,就是遍历过程中,每次添加一个元素后,就将n 减去当前元素,然后递归去拿下一个元素,直到本次path中够了k个元素,就是终止条件了。

判断和是否等于0了,等于则加进去result。

关于剪枝,两个操作:

  • 和求全部组合一样,遍历的终止条件,如果剩余集合的元素已经不符合k-path.length个元素了,就不需要再继续遍历了。
  • 如果递归前,当前减去的和已经小于0,说明不符合条件,要回退当前元素,直接返回
/**
 * @param {number} k
 * @param {number} n
 * @return {number[][]}
 */
var combinationSum3 = function(k, n) {
    const result = [];
    const path = [];
    const combine = (k, targetSum, startIndex) => {
        if (path.length === k) {
            if (targetSum === 0) {
                result.push(path.slice());
            }
            return;
        }
        for (let i = startIndex; i <= 9 - (k - path.length) + 1; i++) {
            path.push(i);
            targetSum -= i;
            if (targetSum < 0) {
                path.pop();
                targetSum += i;
                return;
            }
            combine(k, targetSum, i + 1);
            path.pop();
            targetSum += i;
        }
    }
    combine(k, n, 1);
    return result
};

题目2 17. 电话号码的字母组合

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

思路

这个和上个的区别,这个相当于不同集合求组合,给到的digits的长度就是递归的深度,首先把数字和字母集合映射表写出来,

  • 终止条件:path的长度等于digits的长度,将path放进去
  • 参数:遍历到了第几个数字,每次取出来数字对应的字母集合
  • 单层逻辑:遍历当前层的字母集合, 这里是全部遍历,path放进去一个,再递归去下一个字母集合中选字母,整个递归完成后,将当前字母pop,开始遍历下一个字母的所有集合。
var letterCombinations = function(digits) {
    const digitMap = {
       2: 'abc',
       3: 'def',
       4: 'ghi',
       5: 'jkl',
       6: 'mno',
       7: 'pqrs',
       8: 'tuv',
       9: 'wxyz' 
    }
    const result = [];
    const path = [];
    const letterCombine = (digits, index) => {
        if (path.length === digits.length) {
            if (path.length) {
                result.push(path.join(''))
            }
            return;
        }
        const digit = digits[index];
        const letters = digitMap[digit];
        for (let i = 0; i < letters.length; i++) {
            path.push(letters[i]);
            letterCombine(digits, index + 1);
            path.pop();
        }
    }
    letterCombine(digits, 0);
    return result;
};