Skip to content

Commit dec9da9

Browse files
committed
feat: implement combinationSum function using DFS/backtracking with detailed comments on approach and complexity
1 parent 6944cfd commit dec9da9

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

combination-sum/hongseoupyun.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# // Input: candidates = [2,3,5], target = 8
2+
# // Output: [[2,2,2,2],[2,3,3],[3,5]]
3+
4+
# // DFS/backtracking should be used - Find possilbe combinations till the end and backtrack to previous step to find other combinations
5+
# // For example, if we have candidates [2,3,5] and target 8
6+
# // Start with empty combination [], target 8
7+
# // Add 2 -> [2], remaining 6
8+
# // Add 2 -> [2,2], remaining 4
9+
# // Add 2 -> [2,2,2], remaining 2
10+
# // Add 2 -> [2,2,2,2], remaining 0 (found a valid combination)
11+
# // Backtrack to [2,2,2,3], remaining -1 (remaining is negative, backtrack)
12+
# // Backtrack to [2,2,2,5], remaining -3 (remaining is negative, backtrack)
13+
# // Backtrack to [2,2,3], remaining 1 (dead end, backtrack)
14+
# // Backtrack to [2,2,5], remaining -3 (remaining is negative, backtrack)
15+
# // Backtrack to [2,3], remaining 3
16+
# // Add 3 -> [2,3,3], remaining 0 (found a valid combination)
17+
# // so on ..
18+
19+
# // When you dfs, always start from current index and allow reusing the same element or next index only to avoid duplicates / to get unique combination
20+
# // Hence, if we starts from 2, next dfs calls can start from index of 2 or index of 3, but not index of 5 directly
21+
# // Moreover, if we start from 3, next dfs calls can start from index of 3 or index of 5, but not index of 2 directly
22+
23+
24+
25+
from typing import List
26+
27+
class Solution:
28+
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
29+
result: List[List[int]] = []
30+
31+
def backtrack(remaining: int, combination: List[int], start_index: int):
32+
# base cases
33+
if remaining == 0:
34+
# append a COPY of combination
35+
result.append(combination[:])
36+
return
37+
if remaining < 0:
38+
return
39+
40+
# try candidates from start_index onward
41+
for i in range(start_index, len(candidates)):
42+
current_number = candidates[i]
43+
# choose
44+
combination.append(current_number)
45+
# explore (i, not i+1, because we can reuse same element)
46+
backtrack(remaining - current_number, combination, i)
47+
# undo (backtrack)
48+
combination.pop()
49+
50+
# initial call
51+
backtrack(target, [], 0)
52+
return result
53+
54+
55+
56+
57+

combination-sum/hongseoupyun.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Input: candidates = [2,3,5], target = 8
2+
// Output: [[2,2,2,2],[2,3,3],[3,5]]
3+
4+
// DFS/backtracking should be used - Find possilbe combinations till the end and backtrack to previous step to find other combinations
5+
// For example, if we have candidates [2,3,5] and target 8
6+
// Start with empty combination [], target 8
7+
// Add 2 -> [2], remaining 6
8+
// Add 2 -> [2,2], remaining 4
9+
// Add 2 -> [2,2,2], remaining 2
10+
// Add 2 -> [2,2,2,2], remaining 0 (found a valid combination)
11+
// Backtrack to [2,2,2,3], remaining -1 (remaining is negative, backtrack)
12+
// Backtrack to [2,2,2,5], remaining -3 (remaining is negative, backtrack)
13+
// Backtrack to [2,2,3], remaining 1 (dead end, backtrack)
14+
// Backtrack to [2,2,5], remaining -3 (remaining is negative, backtrack)
15+
// Backtrack to [2,3], remaining 3
16+
// Add 3 -> [2,3,3], remaining 0 (found a valid combination)
17+
// so on ..
18+
19+
// When you dfs, always start from current index and allow reusing the same element or next index only to avoid duplicates / to get unique combination
20+
// Hence, if we starts from 2, next dfs calls can start from index of 2 or index of 3, but not index of 5 directly
21+
// Moreover, if we start from 3, next dfs calls can start from index of 3 or index of 5, but not index of 2 directly
22+
23+
24+
function combinationSum(candidates: number[], target: number): number[][] {
25+
const result: number[][] = []
26+
27+
function backtrack(remaining: number, combination: number[], startindex: number) {
28+
// Remaining is target - sum of combination
29+
// Base Case1: If remaining is 0, we found a valid combination -> add that combinations to result
30+
if (remaining === 0) {
31+
result.push([...combination]);
32+
return;
33+
}
34+
35+
// Base Case2: If remaining is negative, no valid combination -> backtrack
36+
if (remaining < 0) {
37+
return;
38+
}
39+
40+
// Explore further by trying each candidate starting from startindex
41+
// candidates = [2,3,5], target = 8
42+
for (let i = startindex; i < candidates.length; i++) {
43+
// Choose the current number
44+
const currentNumber = candidates[i];
45+
// Add the current number to the combination
46+
combination.push(currentNumber);
47+
48+
// Explore further with updated remaining and current combination
49+
backtrack(remaining - currentNumber, combination, i);
50+
// Backtrack: remove the last added candidate to try next candidate
51+
combination.pop();
52+
}
53+
}
54+
backtrack(target, [], 0);
55+
return result;
56+
};

0 commit comments

Comments
 (0)