216. Combination Sum III Medium
Find all valid combinations of k numbers that sum up to n such that the following conditions are true:
- Only numbers
1through9are used. - Each number is used at most once.
Return a list of all possible valid combinations. The list must not contain the same combination twice, and the combinations may be returned in any order.
Example 1:
Input: k = 3, n = 7
Output: [[1,2,4]]
Explanation:
1 + 2 + 4 = 7
There are no other valid combinations.
Example 2:
Input: k = 3, n = 9
Output: [[1,2,6], [1,3,5], [2,3,4]]
Explanation:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
There are no other valid combinations.
Example 3:
Input: k = 4, n = 1
Output: []
Explanation: There are no valid combinations.
Using 4 different numbers in the range [1,9], the smallest sum we can get is 1+2+3+4 = 10 and since 10 > 1, there are no valid combinations.
Approach
Input: Two integers k and n, requiring us to pick k distinct numbers between 1 and 9 that sum to n.
Output: Return all possible combinations (order doesn't matter, but numbers cannot be reused).
This problem belongs to Combination Backtracking problems.
- We start from
9(because available numbers are 1~9 and can't be repeated) and try adding numbers to our path. - Every time a number
jis picked, place it inpath, and update the current sumt. - Continue recursively picking numbers
j-1and below. - If the current path length equals
kand the sum equalsn, we found a valid combination, and we append it toans. - If the current sum goes over
n, or the remaining pool of usable numbers is insufficient to achieve the sum, we prune the search branch straight away.
Three Questions of Backtracking
Current Operation?
- At current index
i(representing the maximum available number), attempt to choose current numberj(j ∈ [i, 1]) and add into traversalpath. - Meaning placing number
jinside the array tracking choices made, indicating "I picked it".
- At current index
Sub-problem?
- After choosing
j, continue to pick among the available downstream values (j-1to1) to fill the rest of the combinations. - Concurrently maintain the sum value tracking
t, looping recursively until exactlyknumbers are collected.
- After choosing
Next Sub-problem?
- The next recursive drill runs
dfs(j-1, t+j), indicating we look sequentially at components starting fromj-1and keeping record of our aggregated sum.
- The next recursive drill runs
Pruning Conditions
- If current sum
tis strictly larger than our target sumn, we can aggressively branch off and return back immediately. - If the remaining pool of items just isn't mathematically fit enough to satisfy the remainder formula (i.e.
(i - d + 1 + i) * d // 2 < n - t), prune returning.
Implementation
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
ans = [] # Store final results
path = [] # The current combination traversal path
# Backtracking worker
def dfs(i, t):
# Pruning 1: If current accumulated payload exceeds expected sum n, prune immediately
if t > n:
return
# Pruning 2: If selecting all remaining maximal allowed digits is less than what is needed to reach target n
# Calculation logic corresponds to summing an arithmetic progression
d = k - len(path)
min_sum = (i - d + 1 + i) * d // 2 # The sum of numbers ranging from i-(d-1) to i
if min_sum < n - t:
return
# Condition met: Handpicked exact target quantity summing neatly exactly
if len(path) == k and t == n:
ans.append(path.copy())
return
# Process candidates branching down from large digits to smallest recursively
for j in range(i, 0, -1):
path.append(j) # Pick candidate `j`
dfs(j - 1, t + j) # Branch down selecting components with limits adjusted beneath candidate
path.pop() # Take pick out of consideration recursively
dfs(9, 0) # Recurse starting from upper bounds `9`
return ans/**
* @param {number} k
* @param {number} n
* @return {number[][]}
*/
const combinationSum3 = function(k, n) {
const ans = [];
const path = [];
function dfs(i, t) {
if (t > n) return;
const d = k - path.length;
if ((i - d + 1 + i) * d / 2 < n - t) return;
if (path.length == k && t == n) {
ans.push([...path]);
return;
}
for (let j = i; j > 0; j --) {
path.push(j);
dfs(j - 1, t + j);
path.pop()
}
}
dfs(9, 0);
return ans;
};Complexity Analysis
- Time Complexity:
O(k * 9^k)(ActuallyO(C(9,k) * k)which is very small) - Space Complexity:
O(k)