let k = 4, n = 10; let combinationSum3 = function (k, n) { let number = [[]]; let ary = [] let numbers = [...Array(9)].map((item, index) => index + 1) for (let i = 0; i < numbers.length + 1; i++) { let turn = number.map(v => [...v, numbers[i]]) number = number.concat(turn); } for (let i = 0; i < number.length; i++) { if (number[i].length === k) { if (sum(number[i]) === n) { ary.push(number[i]) } } } return ary;ary };
如果当前组合数组的长度超过了题目给定的k,那么没有必要继续回溯,进行剪纸 由于遍历[start, 9]的过程中,我们是从小到大排序的,那么如果当前的组合总和sum加上了[start, 9]中的某个数字num后,使得sum + num > n,这里假设num的下标是i,那么很明显,[i, 9]区间的数字就没有必要再遍历回溯了,因为什么组合的和都会大于n,进行剪纸。 于是可以写出代码如下:
let k = 3, n = 10;
let ans; let combinationSum3 = function (k, n) { ans = []; back(k, n, [], 0, 1); return ans; };
/* * @params {Array} nowArr 当前回溯组合 * @params {number} sum 当前回溯组合的总和 * @params {number} start 下次回溯的起点坐标 */ functionback(k, n, nowArr, sum, start) { // 符合双重条件 if (nowArr.length === k && sum === n) { return ans.push(nowArr); } // 递归找到合适的数组 for (let i = start; i <= 9; i++) { if (sum + i > n || nowArr.length > k) break; back(k, n, [...nowArr, i], sum + i, i + 1); } }