给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
对于这类寻找所有可行解的题,我们都可以尝试用「搜索回溯」的方法来解决。
**我们定义递归函数 dfs(target,combine,idx),表示当前在 candidates数组的第 idx位,还剩 target要组合,已经组合的列表为 combine。**递归的终止条件为 target <= 0 或者 candidates的元素全部用完。
那么在当前函数中,每次我们可以选择不使用idx位置的数据,即执行dfs(target,combine,idx+1),也可以选择使用idx位置数据,即执行dfs(target-candidates[idx],combine,idx),注意到每个数字可以被无限制重复选取,因此搜索的下标仍为 idx。
复杂度分析
时间复杂度:O(S),其中 S 为所有可行解的长度之和。
空间复杂度:O(target),极限情况下递归的层数为target层,因此所需要的栈空间至多有target个。
执行示例如下:
/*
典型的回溯+递归,太经典了,代码很美
*/
func combinationSum(_ candidates: [Int], _ target: Int) -> [[Int]] {
var ans = [[Int]]()
var combine = [Int]()
dfs(candidates, target, &ans, &combine, 0)
return ans
}
func dfs(_ candidates: [Int], _ target: Int, _ ans: inout [[Int]], _ combine: inout [Int], _ idx: Int) {
//定义递归的终止条件:1.到达数据末尾; 2.target为0
if idx == candidates.count {
return
}
if target == 0 {
ans.append(combine)
return
}
//直接跳过,递归下一个
dfs(candidates, target, &ans, &combine, idx+1)
if target - candidates[idx] >= 0 {
//尝试用candidates[idx]解题
combine.append(candidates[idx])
dfs(candidates, target-candidates[idx], &ans, &combine, idx)
let _ = combine.popLast()
}
}
- (NSArray *)combinationSum:(NSArray *)candidates target:(NSInteger)target {
NSMutableArray <NSArray <NSNumber *>*>*ans = [NSMutableArray array];
NSMutableArray <NSNumber *>*combine = [NSMutableArray array];
[self dfs:candidates targe:target ans:ans combine:combine idx:0];
return ans;
}
- (void)dfs:(NSArray *)candidates
targe:(NSInteger)target
ans:(NSMutableArray *)ans
combine:(NSMutableArray *)combine
idx:(NSInteger)idx {
//定义递归终止条件
if (idx == candidates.count) {
return;
}
if (target == 0) {
[ans addObject:combine];
return;
}
//直接跳过,递归下一个
[self dfs:candidates targe:target ans:ans combine:combine idx:idx+1];
if (target - [candidates[idx] integerValue] >= 0) {
[combine addObject:candidates[idx]];
[self dfs:candidates targe:target-[candidates[idx] integerValue] ans:ans combine:combine idx:idx];
[combine removeLastObject];
}
}