216. 组合总和 III
216. 组合总和 III
题意
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
所有数字都是正整数。
解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解题思路
由于最终的结果要求是有序的,因此需要先将数组进行排序;
回溯:维持一个路径组合,并且不断的将target减去数组中的值,直到target值为0,则把路径组合加入到最终的结果中;
记忆化搜索:通过字典记录下每个和对应的组合,在target在不断减去数组中的值的时候,如果这个和已经出现过,那么直接返回该和对应的组合,由于新的组合是在前面的组合的基础上进行操作的,所以没有办法对前面的组合进行剪枝;
动态规划:应该也是和2类似的思想;
实现
之前以为回溯都需要有值返回😳,下面为有返回值的和没有返回值的做法。
class Solution(object):
def combinationSum3(self, k, target):
"""
回溯
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
candidates = [i for i in range(1, 10)]
nums_len = len(candidates)
def helper(depth, index, target, path):
# 边界条件为剩余关键字减到了0,表明path中的值的和已经满足条件
if depth == k:
if not target:
res.append(path)
return
for idx in range(index, nums_len):
# 如果剩余关键字比当前数字还要小的话,后面就没有循环的必要了
# 所以从idx后面的继续找;
if candidates[idx] in path:
continue
if target >= candidates[idx]:
helper(depth+1, idx+1, target - candidates[idx], path + [candidates[idx]])
else:
break
helper(0, 0, target, [])
return res
def combinationSum3(self, k, target):
"""
记忆化搜索
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
# 记录每个和对应的组合
memorize = {}
candidates = [i for i in range(1, 10)]
def helper(target):
if target in memorize:
return memorize[target]
new_conbinations = []
for num in candidates:
if num > target:
break
elif num == target:
new_conbinations.append([num])
else:
old_conbinations = helper(target-num)
for conbination in old_conbinations:
if num > conbination[0] or num in conbination:
continue
# 由于不能够确保num是否是正确的,能够加入到结果数组中,并且数组是可变对象
# 因此不能够将num append 到数组中
# 加入到前面是因为可以保证顺序,这是因为循环是从小到大的顺序来找出对应的target
new_conbinations.append([num] + conbination)
memorize[target] = new_conbinations
return new_conbinations
helper(target)
return filter(lambda conbination: len(conbination) == k, memorize[target])
关注公众号:数据结构与算法那些事儿,每天一篇数据结构与算法