题意
给定数组candidates及数字target,找出所有能和为target的组合方式。
hint:
每个组合中candidate中的元素只能使用一次,ex. candidates中有两个1,那么每个组合方式中1最多只能出现两次;
candidatas中可能包含重复元素;
重复的组合方式保留其一即可;
解法
对于这种没有明确思路,又要找出所有解法的题目,显然搜索是可以解决的。
class Solution:
def __init__(self):
self.results = []
self.nums = []
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
self.nums = sorted(candidates)
self.recursive(0, target, [])
new_results = []
for result in self.results:
if result not in new_results:
new_results.append(result)
return new_results
def recursive(self, index, target, parts):
if target == 0:
self.results.append(parts)
if index >= len(self.nums) or target < self.nums[index]:
return
for i in range(index, len(self.nums)):
new_parts = parts.copy()
next_num = self.nums[i]
new_parts.append(next_num)
self.recursive(i + 1, target - self.nums[i], new_parts)
很不幸,上面的代码超时了,观察下被卡的数据点,是一个candidates是一个长度24,全为1的数组,target为27。
加一个数组总和小于target的剪枝?显然不够,如果candidates是长度27,全为1的数组,照样会超时。
上面代码的超时原因不是在搜索有效解上浪费的,而是在搜索中没能避开重复解浪费的。
简而言之,在搜索时,parts长度相同时,如果当前选择的next_candidate和上一次选择的last_candidate相同,新的这次搜索必不会产生新解。
优化重复解的判断逻辑, AC。
class Solution:
def __init__(self):
self.results = []
self.nums = []
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
self.nums = sorted(candidates)
self.recursive(0, target, [])
return self.results
def recursive(self, index, target, parts):
if target == 0:
self.results.append(parts)
if index >= len(self.nums) or target < self.nums[index]:
return
last_num = None
for i in range(index, len(self.nums)):
if self.nums[i] != last_num:
new_parts = parts.copy()
next_num = self.nums[i]
new_parts.append(next_num)
self.recursive(i + 1, target - self.nums[i], new_parts)
last_num = self.nums[i]