leecode/problems/39.combination-sum.md
2020-05-22 18:17:19 +08:00

181 lines
4.9 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 题目地址
https://leetcode.com/problems/combination-sum/description/
## 题目描述
```
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
Example 2:
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
```
## 思路
这道题目是求集合,并不是`求极值`,因此动态规划不是特别切合,因此我们需要考虑别的方法。
这种题目其实有一个通用的解法,就是回溯法。
网上也有大神给出了这种回溯法解题的
[通用写法](https://leetcode.com/problems/combination-sum/discuss/16502/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partitioning)),这里的所有的解法使用通用方法解答。
除了这道题目还有很多其他题目可以用这种通用解法,具体的题目见后方相关题目部分。
我们先来看下通用解法的解题思路,我画了一张图:
![backtrack](../assets/problems/backtrack.png)
通用写法的具体代码见下方代码区。
## 关键点解析
- 回溯法
- backtrack 解题公式
## 代码
* 语言支持: JavascriptPython3
```js
/*
* @lc app=leetcode id=39 lang=javascript
*
* [39] Combination Sum
*
* https://leetcode.com/problems/combination-sum/description/
*
* algorithms
* Medium (46.89%)
* Total Accepted: 326.7K
* Total Submissions: 684.2K
* Testcase Example: '[2,3,6,7]\n7'
*
* Given a set of candidate numbers (candidates) (without duplicates) and a
* target number (target), find all unique combinations in candidates where the
* candidate numbers sums to target.
*
* The same repeated number may be chosen from candidates unlimited number of
* times.
*
* Note:
*
*
* All numbers (including target) will be positive integers.
* The solution set must not contain duplicate combinations.
*
*
* Example 1:
*
*
* Input: candidates = [2,3,6,7], target = 7,
* A solution set is:
* [
* [7],
* [2,2,3]
* ]
*
*
* Example 2:
*
*
* Input: candidates = [2,3,5], target = 8,
* A solution set is:
* [
* [2,2,2,2],
* [2,3,3],
* [3,5]
* ]
*
*/
function backtrack(list, tempList, nums, remain, start) {
if (remain < 0) return;
else if (remain === 0) return list.push([...tempList]);
for (let i = start; i < nums.length; i++) {
tempList.push(nums[i]);
backtrack(list, tempList, nums, remain - nums[i], i); // 数字可以重复使用, i + 1代表不可以重复利用
tempList.pop();
}
}
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum = function(candidates, target) {
const list = [];
backtrack(list, [], candidates.sort((a, b) => a - b), target, 0);
return list;
};
```
Python3 Code:
```python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
"""
回溯法,层层递减,得到符合条件的路径就加入结果集中,超出则剪枝;
主要是要注意一些细节,避免重复等;
"""
size = len(candidates)
if size <= 0:
return []
# 先排序,便于后面剪枝
candidates.sort()
path = []
res = []
self._find_path(target, path, res, candidates, 0, size)
return res
def _find_path(self, target, path, res, candidates, begin, size):
"""沿着路径往下走"""
if target == 0:
res.append(path.copy())
else:
for i in range(begin, size):
left_num = target - candidates[i]
# 如果剩余值为负数,说明超过了,剪枝
if left_num < 0:
break
# 否则把当前值加入路径
path.append(candidates[i])
# 为避免重复解,我们把比当前值小的参数也从下一次寻找中剔除,
# 因为根据他们得出的解一定在之前就找到过了
self._find_path(left_num, path, res, candidates, i, size)
# 记得把当前值移出路径,才能进入下一个值的路径
path.pop()
```
## 相关题目
- [40.combination-sum-ii](./40.combination-sum-ii.md)
- [46.permutations](./46.permutations.md)
- [47.permutations-ii](./47.permutations-ii.md)
- [78.subsets](./78.subsets.md)
- [90.subsets-ii](./90.subsets-ii.md)
- [113.path-sum-ii](./113.path-sum-ii.md)
- [131.palindrome-partitioning](./131.palindrome-partitioning.md)