Generate All Combinations Sum K in DSA Typescript - Time & Space Complexity
We want to understand how the time needed to find all combinations that add up to a target grows as the input changes.
Specifically, how does the number of combinations affect the work done?
Analyze the time complexity of the following code snippet.
function combinationSumK(nums: number[], k: number): number[][] {
const result: number[][] = [];
function backtrack(start: number, target: number, path: number[]) {
if (target === 0) {
result.push([...path]);
return;
}
for (let i = start; i < nums.length; i++) {
if (nums[i] > target) continue;
path.push(nums[i]);
backtrack(i + 1, target - nums[i], path);
path.pop();
}
}
backtrack(0, k, []);
return result;
}
This code finds all unique combinations of numbers from the array that add up exactly to k.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive backtracking exploring combinations.
- How many times: Potentially explores many subsets, depending on input size and target.
As input size grows, the number of possible combinations grows very fast.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Up to thousands of recursive calls |
| 20 | Up to millions of recursive calls |
| 30 | Potentially billions of recursive calls |
Pattern observation: The work grows exponentially because each number can be chosen or skipped, creating many combinations.
Time Complexity: O(2^n * k)
This means the time needed can double with each additional number, as all subsets might be explored, and each valid combination can take up to O(k) time to copy.
[X] Wrong: "The time grows linearly with the input size because we just loop through the array once."
[OK] Correct: The code uses recursion to explore many combinations, not just a single loop, so the time grows much faster than linear.
Understanding this helps you explain how recursive solutions explore many possibilities and why some problems need careful time complexity reasoning.
"What if we allowed numbers to be reused unlimited times? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem goal
The problem asks to find all unique sets of numbers whose sum equals K.Step 2: Clarify uniqueness and sum condition
Each combination must sum exactly to K without duplicates in the result.Final Answer:
All unique combinations of numbers that add up to K -> Option CQuick Check:
Combinations sum to K = All unique combinations of numbers that add up to K [OK]
- Confusing sum with count
- Including duplicate combinations
- Looking for single numbers only
Solution
Step 1: Analyze parameter types
The function should take an array of numbers and a target number.Step 2: Analyze return type
It should return an array of arrays of numbers representing combinations.Final Answer:
function generateCombinations(nums: number[], target: number): number[][] -> Option BQuick Check:
Input array and target number, output array of number arrays [OK]
- Using wrong parameter types
- Returning flat array instead of array of arrays
- Mixing string and number types
function combineSum(nums: number[], target: number): number[][] {
const result: number[][] = [];
function backtrack(start: number, path: number[], sum: number) {
if (sum === target) {
result.push([...path]);
return;
}
if (sum > target) return;
for (let i = start; i < nums.length; i++) {
path.push(nums[i]);
backtrack(i + 1, path, sum + nums[i]);
path.pop();
}
}
backtrack(0, [], 0);
return result;
}
console.log(combineSum([1, 2, 3], 3));Solution
Step 1: Trace backtracking calls
Starting from 0, combinations are built adding numbers without reuse: [1,2] sums to 3, [3] sums to 3.Step 2: Confirm valid combinations
Other combinations like [2] or [1,3] do not sum to 3 or are invalid due to index increment.Final Answer:
[[1, 2], [3]] -> Option AQuick Check:
Combinations summing to 3 = [[1, 2], [3]] [OK]
- Including combinations with reused elements
- Ignoring sum > target condition
- Confusing order of elements
function findCombos(nums: number[], target: number): number[][] {
const res: number[][] = [];
function dfs(i: number, path: number[], total: number) {
if (total === target) {
res.push(path);
return;
}
if (total > target || i === nums.length) return;
dfs(i + 1, path, total);
path.push(nums[i]);
dfs(i + 1, path, total + nums[i]);
path.pop();
}
dfs(0, [], 0);
return res;
}Solution
Step 1: Check how path is stored
The path array is pushed directly without copying, so later changes affect stored results.Step 2: Understand impact on results
Because path is referenced, all stored combinations end up empty or incorrect after backtracking.Final Answer:
The path array is pushed by reference causing incorrect results -> Option DQuick Check:
Push copy of path, not reference [OK]
- Pushing path without copying
- Not handling base cases properly
- Incorrect index increment
nums = [1, 2, 2, 3], target = 4
Solution
Step 1: Sort the input array
Sorting groups duplicates together, making it easier to skip them during recursion.Step 2: Skip duplicates in recursion
When iterating, skip elements equal to the previous to avoid duplicate combinations.Final Answer:
Sort the array and skip duplicates during recursion -> Option AQuick Check:
Sorting + skipping duplicates = unique combinations [OK]
- Not sorting before recursion
- Filtering duplicates after generation (inefficient)
- Ignoring duplicates causing repeated results
Ready to prove it?
Pass the test and this pattern moves unknown
