-
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。