Leetcode Daily Question 13/08/2024 - 40. Combination Sum II
Problem Description:
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target. Each number in candidates may only be used once in the combination. Note: The solution set must not contain duplicate combinations.
Solution:
from typing import List
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
result = []
path = []
candidates.sort()
def dfs(start, target):
if target == 0:
result.append(path[:])
if target < 0:
return
for i in range(start, len(candidates)):
if i > start and candidates[i] == candidates[i-1]:
continue
if candidates[i] > target:
break
path.append(candidates[i])
dfs(i + 1, target - candidates[i])
path.pop()
dfs(0, target)
return result
Explanation:
To solve this problem, we can use dfs to explore all paths. A useful adjustment to make is to sort the candidates so that we can traverse all the paths continuously without terminating early.
Let's consider the following example.
candidates = [10,1,2,7,6,1,5]
target = 8
#sort the candidates
candidates = [1,1,2,5,6,7,10]
#DFS
Start at index 0, target = 8, and an empty path
We add 1 to the path, then we call dfs again to check.
Since 1 < 8, target now becomes 7 > 0, so we move on to the next index and add it to the path.
path = [1,1]. Target = 6 > 0, path = [1,1,2]. Target = 4, path = [1,1,2,5].
Now, target = 4 - 5 = -1 < 0, we cannot continue this path, so we pop the last added element, path = [1,1,2]
path = [1,1,2,7], target = -3 < 0, so path again returns to [1,1,2]
path = [1,1,2,10] target = -6 < 0, so path returns to [1,1,2].
Since we have explored all possible paths of this configuration we pop the last element and add the next element.
path -> [1,1] -> [1,1,5]
Continue as befoe, [1,1,5,7] means target < 0 so path returns to [1,1,5].
#We can avoid extra calculations by:
# - skipping elements if they are already bigger than the target
# - skipping elements if they constitue duplicated start points.
Putting this into code, we have.
def dfs(start, target):
if target == 0:
result.append(path[:])
return
if target < 0:
return
for i in range(start, len(candidates)):
if i > start and candidates[i-1] == candidates[i]: #This ensures we dont need to explore duplicated paths.
continue
if candidates[i] > target: #no need to explore paths starting with elements larger than target.
break
path.append(candidates[i])
dfs(i+1, target - candidates[i])
path.pop()
We just need to declare the starting conditions and return result.
def combinationSum2(candidates, target):
result = []
path = []
candidates.sort()
#INSERT DFS FUNCTION...
dfs(0, target)
return result
The final solution can be found near the top of the page.