Combination Sum with Restrictions — Problem Statement & Solution Guide
Problem Description
Given an array of integers asteroids representing the number of gems in each asteroid and a target total of gems targetGems, find all unique combinations of asteroids that sum up to targetGems, with the restriction that no asteroid can be used more than once and each asteroid type can only be used as many times as it appears in the array.
Examples
Input
[1, 2, 3, 4, 5], 7
Output
[[1, 2, 4], [1, 3, 3], [2, 2, 3], [2, 5], [3, 4]]
Explanation: Step-by-step: with input [1, 2, 3, 4, 5], targetGems = 7, we first sort the asteroids array. Then, we start with the smallest asteroid and recursively try to find combinations that sum up to the targetGems. We use a backtracking approach to avoid duplicate combinations.
Input
[1, 2, 3, 4, 5], 10
Output
[[1, 2, 3, 4], [1, 2, 5], [1, 3, 6], [2, 2, 6], [2, 3, 5], [2, 4, 4], [3, 3, 4], [4, 4, 2], [5, 5]]
Explanation: Step-by-step: with input [1, 2, 3, 4, 5], targetGems = 10, we first sort the asteroids array. Then, we start with the smallest asteroid and recursively try to find combinations that sum up to the targetGems. We use a backtracking approach to avoid duplicate combinations.
Constraints
- The number of asteroids will not exceed 10.
- The target number of gems will be between 1 and 100.
- Each asteroid contains between 1 and 50 gems.
Optimal Approach & Strategy
The optimal approach involves using a recursive backtracking function with pruning to efficiently explore the search space and find all valid combinations of asteroids, achieving an improved time complexity of O(N*2^N) in the worst case. It utilizes a sorted array to prioritize larger gems and minimize the search space.
Brute Force Approach
A naive approach would involve generating all possible combinations of asteroids and checking each one to see if it sums up to the target number of gems, resulting in an inefficient O(2^n) complexity. This approach is impractical for large inputs. It would require iterating over all possible subsets of the asteroids array.
Verified Code Solutions
function combinationSumWithRestrictions(asteroids, targetGems) {
const n = asteroids.length;
const countMap = new Map();
for (let i = 0; i < n; i++) {
countMap.set(asteroids[i], (countMap.get(asteroids[i]) || 0) + 1);
}
const result = [];
function backtrack(start, path, target) {
if (target === 0) {
result.push([...path]);
return;
}
for (let i = start; i <= n; i++) {
const asteroid = asteroids[i - 1];
const count = countMap.get(asteroid);
if (count > 0 && target >= asteroid) {
path.push(asteroid);
countMap.set(asteroid, count - 1);
backtrack(i + 1, path, target - asteroid);
path.pop();
countMap.set(asteroid, count);
}
}
}
backtrack(1, [], targetGems);
return result;
}class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
Set<List<Integer>> result = new HashSet<>();
backtrack(target, new ArrayList<>(), 0, candidates, result);
return new ArrayList<>(result);
}
private void backtrack(int remain, List<Integer> comb, int start, int[] candidates, Set<List<Integer>> result) {
if (remain == 0) {
result.add(new ArrayList<>(comb));
return;
}
for (int i = start; i < candidates.length; i++) {
if (i > start && candidates[i] == candidates[i - 1]) {
continue;
}
if (candidates[i] > remain) {
break;
}
backtrack(remain - candidates[i], new ArrayList<>(comb) {{ add(candidates[i]); }}, i + 1, candidates, result);
}
}
}def combinationSum2(candidates, target):
candidates.sort()
def backtrack(remain, comb, start):
if remain == 0:
result.add(tuple(sorted(comb)))
return
for i in range(start, len(candidates)):
if i > start and candidates[i] == candidates[i - 1]:
continue
if candidates[i] > remain:
break
backtrack(remain - candidates[i], comb + [candidates[i]], i + 1)
result = set()
backtrack(target, [], 0)
return [list(x) for x in result]function combinationSumWithRestrictions(asteroids, targetGems) {
const n = asteroids.length;
const countMap = new Map();
for (let i = 0; i < n; i++) {
countMap.set(asteroids[i], (countMap.get(asteroids[i]) || 0) + 1);
}
const result = [];
function backtrack(start, path, target) {
if (target === 0) {
result.push([...path]);
return;
}
for (let i = start; i <= n; i++) {
const asteroid = asteroids[i - 1];
const count = countMap.get(asteroid);
if (count > 0 && target >= asteroid) {
path.push(asteroid);
countMap.set(asteroid, count - 1);
backtrack(i + 1, path, target - asteroid);
path.pop();
countMap.set(asteroid, count);
}
}
}
backtrack(1, [], targetGems);
return result;
}Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.