# 组合总数
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 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]
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 方法1: 回溯加剪枝
// https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
var combinationSum = function (candidates, target) {
let size = candidates.length
if (size === 0) {
return []
}
// 剪枝的前提是数组元素排序
// 深度深的边不能比深度浅的边还小
// 要排序的理由:1、前面用过的数后面不能再用;2、下一层边上的数不能小于上一层边上的数。
candidates.sort()
// 在遍历的过程中记录路径,一般而言它是一个栈
let path = []
let res = []
// 注意要传入 size ,在 range 中, size 取不到
dfs(candidates, 0, size, path, res, target)
return res
}
function dfs (candidates, begin, size, path, res, target) {
// 先写递归终止的情况
if (target === 0) {
// js 中可变对象是引用传递,因此需要将当前 path 里的值拷贝出来,避免后续修改 path 影响 res,但是不能丢掉 res 的饮用
res.push([...path])
}
for (let index = begin; index < size; index++) {
let residue = target - candidates[index]
// “剪枝”操作,不必递归到下一层,并且后面的分支也不必执行
if (residue < 0) {
break
}
path.push(candidates[index])
// 因为下一层不能比上一层还小,起始索引还从 index 开始
dfs(candidates, index, size, path, res, residue)
path.pop() // dfs 后,不论成功与否都将上一个结果的值删除
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 方法2: 将两个方法何为一个
var combinationSum = function (candidates, target) {
let size = candidates.length
if (size === 0) {
return []
}
// 剪枝的前提是数组元素排序
// 深度深的边不能比深度浅的边还小
// 要排序的理由:1、前面用过的数后面不能再用;2、下一层边上的数不能小于上一层边上的数。
candidates.sort((a, b) => a - b)
// 在遍历的过程中记录路径,一般而言它是一个栈
let path = []
let res = []
function dfs(path, target, begin) {
// 先写递归终止的情况
if (target === 0) {
// js 中可变对象是引用传递,因此需要将当前 path 里的值拷贝出来,避免后续修改 path 影响 res,但是不能丢掉 res 的饮用
res.push([...path])
}
for (let index = begin; index < size; index++) {
let residue = target - candidates[index]
// “剪枝”操作,不必递归到下一层,并且后面的分支也不必执行
if (residue < 0) {
break
}
path.push(candidates[index])
// 因为下一层不能比上一层还小,起始索引还从 index 开始
dfs(path, residue, index)
path.pop() // dfs 后,不论成功与否都将上一个结果的值删除
}
}
// 注意要传入 size ,在 range 中, size 取不到
dfs(path, target, 0)
return res
}
console.log(combinationSum([2,3,6,7], 7))
console.log(combinationSum([2,3,5], 8))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40