|
1 |
| -""" |
2 |
| -In the Combination Sum problem, we are given a list consisting of distinct integers. |
3 |
| -We need to find all the combinations whose sum equals to target given. |
4 |
| -We can use an element more than one. |
| 1 | + """ |
| 2 | +Combination Sum Problem |
5 | 3 |
|
6 |
| -Time complexity(Average Case): O(n!) |
| 4 | +Description: |
| 5 | +Given a list of distinct integers (candidates), find all unique combinations where the sum of elements equals the given target. |
| 6 | +An element can be used multiple times in a combination. |
7 | 7 |
|
8 | 8 | Constraints:
|
9 | 9 | 1 <= candidates.length <= 30
|
10 | 10 | 2 <= candidates[i] <= 40
|
11 | 11 | All elements of candidates are distinct.
|
12 | 12 | 1 <= target <= 40
|
13 |
| -""" |
14 | 13 |
|
| 14 | +Time complexity (Average Case): O(n!) |
| 15 | +""" |
15 | 16 |
|
16 | 17 | def backtrack(
|
17 |
| - candidates: list, path: list, answer: list, target: int, previous_index: int |
| 18 | + candidates: list[int], |
| 19 | + path: list[int], |
| 20 | + answer: list[list[int]], |
| 21 | + target: int, |
| 22 | + start_index: int |
18 | 23 | ) -> None:
|
19 | 24 | """
|
20 |
| - A recursive function that searches for possible combinations. Backtracks in case |
21 |
| - of a bigger current combination value than the target value. |
| 25 | + Recursive helper function to find all valid combinations. |
22 | 26 |
|
23 |
| - Parameters |
| 27 | + Parameters: |
24 | 28 | ----------
|
25 |
| - previous_index: Last index from the previous search |
26 |
| - target: The value we need to obtain by summing our integers in the path list. |
27 |
| - answer: A list of possible combinations |
28 |
| - path: Current combination |
29 |
| - candidates: A list of integers we can use. |
| 29 | + candidates : list[int] |
| 30 | + A list of distinct integers we can use to form combinations. |
| 31 | + path : list[int] |
| 32 | + The current combination being formed. |
| 33 | + answer : list[list[int]] |
| 34 | + The list of valid combinations that sum to the target. |
| 35 | + target : int |
| 36 | + The remaining sum needed to reach the target. |
| 37 | + start_index : int |
| 38 | + The index to start searching from in the candidates list. |
| 39 | +
|
| 40 | + Returns: |
| 41 | + ------- |
| 42 | + None |
30 | 43 | """
|
31 | 44 | if target == 0:
|
32 | 45 | answer.append(path.copy())
|
33 |
| - else: |
34 |
| - for index in range(previous_index, len(candidates)): |
35 |
| - if target >= candidates[index]: |
36 |
| - path.append(candidates[index]) |
37 |
| - backtrack(candidates, path, answer, target - candidates[index], index) |
38 |
| - path.pop(len(path) - 1) |
| 46 | + return |
39 | 47 |
|
| 48 | + for i in range(start_index, len(candidates)): |
| 49 | + if candidates[i] <= target: |
| 50 | + path.append(candidates[i]) |
| 51 | + backtrack(candidates, path, answer, target - candidates[i], i) # Same index for reuse |
| 52 | + path.pop() # Backtrack |
40 | 53 |
|
41 |
| -def combination_sum(candidates: list, target: int) -> list: |
| 54 | +def combination_sum(candidates: list[int], target: int) -> list[list[int]]: |
42 | 55 | """
|
| 56 | + Finds all unique combinations of candidates that sum up to the target. |
| 57 | +
|
| 58 | + Parameters: |
| 59 | + ---------- |
| 60 | + candidates : list[int] |
| 61 | + A list of distinct integers. |
| 62 | + target : int |
| 63 | + The target sum we want to achieve. |
| 64 | +
|
| 65 | + Returns: |
| 66 | + ------- |
| 67 | + list[list[int]] |
| 68 | + A list of all unique combinations. |
| 69 | +
|
| 70 | + Examples: |
| 71 | + -------- |
43 | 72 | >>> combination_sum([2, 3, 5], 8)
|
44 | 73 | [[2, 2, 2, 2], [2, 3, 3], [3, 5]]
|
45 | 74 | >>> combination_sum([2, 3, 6, 7], 7)
|
46 | 75 | [[2, 2, 3], [7]]
|
47 |
| - >>> combination_sum([-8, 2.3, 0], 1) |
48 |
| - Traceback (most recent call last): |
49 |
| - ... |
50 |
| - RecursionError: maximum recursion depth exceeded |
| 76 | + >>> combination_sum([], 7) |
| 77 | + [] |
| 78 | + >>> combination_sum([1], 0) |
| 79 | + [] |
51 | 80 | """
|
52 |
| - path = [] # type: list[int] |
53 |
| - answer = [] # type: list[int] |
54 |
| - backtrack(candidates, path, answer, target, 0) |
55 |
| - return answer |
| 81 | + if not candidates or target <= 0: |
| 82 | + return [] |
56 | 83 |
|
| 84 | + answer: list[list[int]] = [] |
| 85 | + backtrack(candidates, [], answer, target, 0) |
| 86 | + return answer |
57 | 87 |
|
58 | 88 | def main() -> None:
|
59 |
| - print(combination_sum([-8, 2.3, 0], 1)) |
60 |
| - |
| 89 | + """Main function to test the combination_sum function.""" |
| 90 | + print("Example 1:", combination_sum([2, 3, 5], 8)) |
| 91 | + print("Example 2:", combination_sum([2, 3, 6, 7], 7)) |
| 92 | + print("Example 3 (Invalid input):", combination_sum([], 1)) # Should return [] |
61 | 93 |
|
62 | 94 | if __name__ == "__main__":
|
63 | 95 | import doctest
|
64 |
| - |
65 | 96 | doctest.testmod()
|
66 | 97 | main()
|
0 commit comments