题目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;
};