-
40. 组合总和 II https://leetcode-cn.com/problems/combination-sum-ii/
-
216. 组合总和 III https://leetcode-cn.com/problems/combination-sum-iii/
-
377. 组合总和 Ⅳ https://leetcode-cn.com/problems/combination-sum-iv/
这次对以上组合问题进行总结。题的主旨是对一个数组找到所有和为target的组合形式。题目要求不一,下面一一介绍。
39. 组合总和
数组无重复,每个数字可以被无限次使用,要求返回所有可能的情况(顺序不一样视作一种)。用dfs。
思路:
- 先排序,然后进行遍历。
- 和超过target返回。
- target减到0时把数组加进去。
- 注意去重,比如[1,2]和[2,1]设置加入数必须比之前所有加入的大。
class Solution(object):
def __init__(self):
self.res = []
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
self.res = []
candidates.sort()
self.dfs(candidates, target, [])
return self.res
def dfs(self, candidates, val, temp):
if 0 == val:
self.res.append(temp)
return
if val < 0:
return
for i in range(len(candidates)):
if candidates[i] > val: return
if len(temp) > 0 and candidates[i] < temp[-1]:
continue
self.dfs(candidates, val - candidates[i], temp + [candidates[i]])
return
40. 组合总和 II
数组有重复,每个数字只能被使用一次,要求返回所有可能的情况(顺序不一样视作一种)。用dfs。
思路:
- 先排序,然后进行遍历。
- 和超过target返回,target减到0时把数组加进去。
- 注意去重,比如[1,2]和[2,1]设置加入数必须比之前所有加入的大。
- 此外,因为有重复,所以每次额外传一个参数,表示上一个用到的索引,在这个索引之前(包括这个)都不再进行遍历。
class Solution(object):
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
candidates.sort()
#print candidates
def dfs(val, path, lastind):
if val == 0:# and path not in res:
res.append(path)
return
last = None
for i in range(len(candidates)):
if len(path) > 0 and (candidates[i] < path[-1] or candidates[i] == path[-1] and i <= lastind): #改动
continue
if candidates[i] > val:break
if candidates[i] == last:#改动
continue
dfs(val - candidates[i], path + [candidates[i]], i)
last = candidates[i]
return
dfs(target, [], -1)
return res
216. 组合总和 III
数组被指定为range(1,10),但是要求返回到数组长度都为指定长度k。要求返回所有可能的情况(顺序不一样视作一种)。用dfs。
思路:
- 不需要排序,进行遍历。
- 和超过target返回。
- target减到0且长度等于k时把数组加进去。
- 注意去重,比如[1,2]和[2,1]设置加入数必须比之前所有加入的大。
class Solution(object):
def combinationSum3(self, k, n):
"""
:type k: int
:type n: int
:rtype: List[List[int]]
"""
nums = range(1, 10)
res = []
def dfs(val, path, c):
if len(path) == c:
if val == 0:
res.append(path)
return
for i in range(len(nums)):
if len(path) > 0 and nums[i] <= path[-1]:
continue
if nums[i] > val:
return
dfs(val - nums[i], path + [nums[i]], c)
return
dfs(n, [], k)
return res
377. 组合总和 Ⅳ
数组无重复,每个数字可以被无限次使用,要求返回所有可能的情况(顺序不一样视作不同)的数量。用dfs。
思路:
- 顺序不同视为不同结果,比如[1,1,2],[1,2,1],[2,1,1]为三种不同的情况。
- 因为题只要求返回数量,计数型一般是用递推来做。因为dfs需要更多的复杂度。
- 观察发现递推关系为dp[i] += dp[i - num] for num in nums,即每个数而言,都可以拆分成数组中的一个数和之前dp的另一个数,比如[1,2,4],target=4的情况,dp[4]就可以拆分为1和dp[3]的组合,2和dp[2]的组合,4和dp[0]的组合。
- 这里需要注意dp[0]=1表示空集和数本身的组合,只有一种情况。
class Solution(object):
def combinationSum4(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
dp = [1]
nums.sort()
for i in range(1, target + 1):
temp = 0
for j in range(len(nums)):
if nums[j] > i:
break
temp += dp[i - nums[j]]
dp.append(temp)
#print dp
return dp[-1]
总结
求数量一般按照递推思想来做,而求所有可能情况一般是dfs。