From 8f1d2c8c4578b72b46d74ac262916a02c376adc3 Mon Sep 17 00:00:00 2001 From: "viswajithmangottil@gmail.com" Date: Thu, 23 Oct 2025 20:01:51 +0530 Subject: [PATCH 1/2] Feature: Added a new backtracking question for the better understanding of combination sum --- backtracking/combination_sum_2.py | 81 +++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 backtracking/combination_sum_2.py diff --git a/backtracking/combination_sum_2.py b/backtracking/combination_sum_2.py new file mode 100644 index 000000000000..e5cf7cc68800 --- /dev/null +++ b/backtracking/combination_sum_2.py @@ -0,0 +1,81 @@ +""" +In this Combination Problem, we are given a list consisting of distinct integers. +We need to find all the combinations whose sum equals to target given. +We cannot use an element more than one. + +Time complexity(Average Case): O(n * 2^(n/2)) + + +Constraints: + 1 <= candidates.length <= 100 + 1 <= candidates[i] <= 50 + 1 <= target <= 30 +""" + +def backtrack(candidates: list, target: int, start_index: int, total: int, path: list, answer: list) -> None: + """ + A recursive function that searches for possible combinations. Backtracks in case + of a bigger current combination value than the target value and removes the already + appended values for removing repetition of elements in the solutions. + + Parameters + ---------- + start_index: Last index from the previous search + target: The value we need to obtain by summing our integers in the path list. + answer: A list of possible combinations + path: Current combination + candidates: A list of integers we can use. + total: Sum of elements in path + """ + if target == 0: + answer.append(path.copy()) + return + if total == target: + answer.append(path.copy()) + return + for i in range(start_index, len(candidates)): + if i > start_index and candidates[i] == candidates[i - 1]: + continue + if total + candidates[i] > target: + break + backtrack(candidates, target, i + 1, total + candidates[i], path + [candidates[i]], answer) + + + + +def combination_sum_2(candidates: list,target: int) -> list: + """ + >>> combination_sum_2([10,1,2,7,6,1,5], 8) + [[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]] + >>> combination_sum_2([1,2], 2) + [[2]] + >>> combination_sum_2([-8, 2.3, 0], 1) + Traceback (most recent call last): + ... + ValueError: All elements in candidates must be non-negative + >>> combination_sum_2([], 1) + Traceback (most recent call last): + ... + ValueError: Candidates list should not be empty + """ + if not candidates: + raise ValueError("Candidates list should not be empty") + + if any(x < 0 for x in candidates): + raise ValueError("All elements in candidates must be non-negative") + candidates.sort() + path = [] + answer = [] + backtrack(candidates, target, 0, 0, path, answer) + return answer + + +def main() -> None: + print(combination_sum_2([-8, 2.3, 0], 1)) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + main() \ No newline at end of file From 4495b0389b6c862847c1a510efcf67be9e6a5862 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 15:05:28 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- backtracking/combination_sum_2.py | 51 +++++++++++++++++++------------ 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/backtracking/combination_sum_2.py b/backtracking/combination_sum_2.py index e5cf7cc68800..c8bcb132fc94 100644 --- a/backtracking/combination_sum_2.py +++ b/backtracking/combination_sum_2.py @@ -12,7 +12,15 @@ 1 <= target <= 30 """ -def backtrack(candidates: list, target: int, start_index: int, total: int, path: list, answer: list) -> None: + +def backtrack( + candidates: list, + target: int, + start_index: int, + total: int, + path: list, + answer: list, +) -> None: """ A recursive function that searches for possible combinations. Backtracks in case of a bigger current combination value than the target value and removes the already @@ -38,26 +46,31 @@ def backtrack(candidates: list, target: int, start_index: int, total: int, path: continue if total + candidates[i] > target: break - backtrack(candidates, target, i + 1, total + candidates[i], path + [candidates[i]], answer) - + backtrack( + candidates, + target, + i + 1, + total + candidates[i], + path + [candidates[i]], + answer, + ) - -def combination_sum_2(candidates: list,target: int) -> list: +def combination_sum_2(candidates: list, target: int) -> list: + """ + >>> combination_sum_2([10,1,2,7,6,1,5], 8) + [[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]] + >>> combination_sum_2([1,2], 2) + [[2]] + >>> combination_sum_2([-8, 2.3, 0], 1) + Traceback (most recent call last): + ... + ValueError: All elements in candidates must be non-negative + >>> combination_sum_2([], 1) + Traceback (most recent call last): + ... + ValueError: Candidates list should not be empty """ - >>> combination_sum_2([10,1,2,7,6,1,5], 8) - [[1, 1, 6], [1, 2, 5], [1, 7], [2, 6]] - >>> combination_sum_2([1,2], 2) - [[2]] - >>> combination_sum_2([-8, 2.3, 0], 1) - Traceback (most recent call last): - ... - ValueError: All elements in candidates must be non-negative - >>> combination_sum_2([], 1) - Traceback (most recent call last): - ... - ValueError: Candidates list should not be empty - """ if not candidates: raise ValueError("Candidates list should not be empty") @@ -78,4 +91,4 @@ def main() -> None: import doctest doctest.testmod() - main() \ No newline at end of file + main()