【回溯算法】经典题:求目标和的组合方案 ...
题目描述
这是 LeetCode 上的 40. 组合总和 II,难度为 Medium。
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
示例 2:
DFS + 回溯解法
这道题和「39. 组合总和(中等)」几乎一样。
唯一的不同是这题每个数只能使用一次,而「39. 组合总和(中等)」中可以使用无限次。
我们再来回顾一下应该如何快速判断一道题是否应该使用 DFS + 回溯算法来爆搜。
这个判断方法,最早三叶在 【刷穿 LeetCode】37. 解数独(困难) 讲过。
总的来说,你可以从两个方面来考虑:
1. 求的是所有的方案,而不是方案数。* 由于求的是所有方案,不可能有什么特别的优化,我们只能进行枚举。这时候可能的解法有动态规划、记忆化搜索、DFS + 回溯算法。
2. 通常数据范围不会太大,只有几十。* 如果是动态规划或是记忆化搜索的题的话,由于它们的特点在于低重复/不重复枚举,所以一般数据范围可以出到 $10^5$ 到 $10^7$,而 DFS + 回溯的话,通常会限制在 30 以内。
这道题数据范围是 30 以内,而且是求所有方案。因此我们使用 DFS + 回溯来求解。
我们可以接着 【刷穿 LeetCode】39. 组合总和(中等) 的思路来修改:
由于每个数字只能使用一次,我们可以直接在 DFS 中决策某个数是用还是不用。
由于不允许重复答案,可以使用 set 来保存所有合法方案,最终再转为 list 进行返回。当然我们需要先对 cs 进行排序,确保得到的合法方案中数值都是从小到大的。这样 set 才能起到去重的作用。对于
[1,2,1]
和[1,1,2]
,set 不会认为是相同的数组。
时间复杂度: DFS 回溯算法通常是指数级别的复杂度(因此数据范围通常为 30 以内)。这里暂定 $O(n * 2^n)$
空间复杂度:同上。复杂度为 $O(n * 2^n)$
最后
这是我们「刷穿 LeetCode」系列文章的第 No.40
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode。
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
版权声明: 本文为 InfoQ 作者【宫水三叶的刷题日记】的原创文章。
原文链接:【http://xie.infoq.cn/article/bf38e85b762ba367fc7e324e2】。文章转载请联系作者。
评论