**
**
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
示例 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]
]
此类问题,一定会有一个 target 作为递归结束.
一定会有一个 tmp 用来存放递归回溯中的不同值,可以是nums 或者strs
一定会有一个 index 用来标识,对原输入,遍历到哪里了
每次将“输入”第index的值压入tmp,进行下一轮判断。 然后pop
收敛条件,target 命中,或者 index 到头。
class Solution:
def combinationSum(self, nums: List[int], target: int) -> List[List[int]]:
if len(nums) == 0:
return []
# 剪枝是为了提速,在本题非必需
nums.sort()
# 在遍历的过程中记录路径,它是一个栈
path = []
res = []
# 注意要传入 size ,在 range 中, size 取不到
self.dfs(nums, 0, path, res, target)
return res
def dfs(self, nums, begin, path, res, target):
# 先写递归终止的情况
if target == 0:
# Python 中可变对象是引用传递,因此需要将当前 path 里的值拷贝出来
res.append(path[:])
return
for i in range(begin, len(nums)):
residue = target - nums[i]
# “剪枝”操作,不必递归到下一层,并且后面的分支也不必执行
if residue < 0:
break
path.append(nums[i])
# 因为下一层不能比上一层还小,起始索引还从 index 开始
self.dfs(nums, i, path, res, residue)
path.pop()
思路:根据示例 1:输入: candidates = [2,3,6,7],target = 7。
其实这里思路已经介绍完了,大家可以自己尝试在纸上画一下这棵树。然后编码实现,如果遇到问题,再看下面的文字。
把文字的部分去掉。
如果这样编码的话,会发现提交不能通过,这是因为递归树画的有问题,下面看一下是什么原因。
画出图以后,我看了一下,我这张图画出的结果有 44 个 00,对应的路径是 [[2, 2, 3], [2, 3, 2], [3, 2, 2], [7]],而示例中的解集只有 [[7], [2, 2, 3]],很显然,重复的原因是在较深层的结点值考虑了之前考虑过的元素,因此我们需要设置“下一轮搜索的起点”即可(这里可能没有说清楚,已经尽力了)。
去重复
剪枝提速
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> mem;
fun(candidates,target,0,mem,res);
return res;
}
void fun(const vector<int> &candidates,int target,int index,vector<int> &mem,vector<vector<int>> &res)
//这里将mem定义为引用可以减少占用内存,提高速度。不定义为内存也正确
{
if(target<0) return;
if(target==0)
{
res.push_back(mem);
return;
}
while(index<candidates.size())
{
mem.push_back(candidates[index]);
fun(candidates,target-candidates[index],index,mem,res);
mem.pop_back();
++index;
}
}
};
python 迭代
class Solution(object):
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
candidates = sorted(set(candidates))
result = list()
stack = [(0, list(), target)]
cand_len = len(candidates)
while stack:
i, path, remain = stack.pop()
while i < cand_len:
if path and remain < path[-1]:
break
if candidates[i] == remain:
result.append(path + [candidates[i]])
stack += [(i, path + [candidates[i]], remain - candidates[i])]
i+=1
return result