题目描述
给定一个无重复元素的数组candidates和一个目标数target ,找出candidates中所有可以使数字和为target 的组合。
candidates中的数字可以无限制重复被选取。
说明:
所有数字(包括target)都是正整数。
解集不能包含重复的组合。
示例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]
]
解题思路
首先将candidates[]排序,然后采用递归的方法。
对于任意元素,都有两种情况,选或不选。以candidates[0]为例——
- 选择candidates[0]。由于能重复选择,所以调用:
use_cur = compute(candidates, target - candidates[0])
- 不选candidates[0]。则调用:
no_use_cur = compute(candidates[1:], target)。
由于选择candidates[0]得到结果use_cur,所以use_cur的每个元素都要附加上candidates[0]。最后再附加上no_use_cur。
if use_cur != []:
for list in use_cur:
result.append([candidates[0]] + list)
result = result + no_use_cur
递归到最后,可能性有:
- 最终的candidates[]为空;
- 最终的target小于candidates的最小元素(也就是candidates[0],因为排过序);
- 最终的target等于candidates的最小元素。
备注:只要target还大于candidates[0],就继续递归,直到达到退出条件。
示例代码
combina_sum.py
# -*- coding: utf-8 -*-
class Solution:
"""
给出组合总和的答案
"""
def compute(self, candidates, target):
"""
对于candidates[0],有两种情况
使用本元素
则调用compute(candidates, target - candidates[0])
不使用本元素
则调用compute(candidates[1:], target)
"""
if candidates == []:
return []
if target < candidates[0]:
return []
if target == candidates[0]:
return [[target]]
result = []
use_cur = self.compute(candidates, target - candidates[0])
# 当candidates只有一个元素时,candidates[1:]为[]
no_use_cur = self.compute(candidates[1:], target)
if use_cur != []:
for list in use_cur:
result.append([candidates[0]] + list)
result = result + no_use_cur
return result
def combinationSum(self, candidates, target=0):
"""
解法入口,递归调用compute()方法
:param candidates: List[int]
:param target: int
:return: List[List[int]]
"""
if candidates == []:
return []
candidates.sort()
return self.compute(candidates, target)
test_combination_sum.py
# -*- coding: utf-8 -*-
import unittest
from combination_sum import Solution
class TestCombinationSum(unittest.TestCase):
"""针对Solution类的测试"""
def setUp(self):
"""创建一个Solution类,供使用的测试方法使用"""
self.my_solution = Solution()
def test_empty_list(self):
"""空列表"""
candidates = []
result = self.my_solution.combinationSum(candidates)
expected_result = []
self.assertListEqual(result, expected_result)
def test_target_lt_min_element(self):
"""target小于列表中最小元素"""
candidates = [5, 6, 7]
target = 4
result = self.my_solution.combinationSum(candidates, target)
expected_result = []
self.assertListEqual(result, expected_result)
def test_target_not_get(self):
"""列表中元素组合总和得不到target"""
candidates = [3, 4]
target = 5
result = self.my_solution.combinationSum(candidates, target)
expected_result = []
self.assertListEqual(result, expected_result)
def test_element_use_once(self):
"""列表中元素只用一次"""
candidates = [3, 4]
target = 7
result = self.my_solution.combinationSum(candidates, target)
expected_result = [[3, 4]]
self.assertListEqual(result, expected_result)
def test_element_use_many_times(self):
"""列表中元素用多次"""
candidates = [2, 3]
target = 6
result = self.my_solution.combinationSum(candidates, target)
expected_result = [[2, 2, 2], [3, 3]]
self.assertListEqual(result, expected_result)
if __name__ == '__main__':
unittest.main()