BackmediumBacktrackingMicrosoft

Asteroid Mining Combinations Solution

Problem Statement

Given an integer array nums and an integer target, return every distinct combination of elements from nums whose sum equals target. Each element may be chosen at most once; if a value occurs multiple times in nums it may be used that many times. The output must not contain duplicate combinations (order of numbers inside a combination does not matter). Return the list of combinations in any order.

Example 1
Input
{"nums":[2,3,5,7],"target":7}
Output
[[2,5],[7]]

Explanation: The array contains 2,3,5,7. Combinations that sum to 7 are: 2+5=7 and the single element 7. No other subset reaches 7, and each element is used at most once, so the result is [[2,5],[7]].

Example 2
Input
{"nums":[10,1,2,7,6,1,5],"target":8}
Output
[[1,1,6],[1,2,5],[1,7],[2,6]]

Explanation: After sorting the array we have [1,1,2,5,6,7,10]. Valid subsets that sum to 8 are: 1+1+6, 1+2+5, 1+7, and 2+6. Each uses elements no more times than they appear, and all are unique, giving the four combinations listed.

Example 3
Input
{"nums":[2,4,6,8],"target":8}
Output
[[2,6],[8]]

Explanation: Possible subsets are 2+6=8 and the single element 8. The pair 4+4 is invalid because 4 appears only once in the input. Hence the result is [[2,6],[8]].

Constraints

  • 1 <= nums.length <= 40
  • -100 <= nums[i] <= 100
  • -1000 <= target <= 1000
  • All numbers are integers
Live Compiler1 Free Run Available
Loading Editor...
Test Cases & Output
Click "Run" to test your 1 free compile trial!

🚀 Practice this problem

Run code, get AI hints & track streak

Sign Up Free

Asteroid Mining Combinations — Problem Statement & Solution Guide

BacktrackingMediumMixed
TimeO(2^n)
|
SpaceO(n)

Problem Description

Given an integer array nums and an integer target, return every distinct combination of elements from nums whose sum equals target. Each element may be chosen at most once; if a value occurs multiple times in nums it may be used that many times. The output must not contain duplicate combinations (order of numbers inside a combination does not matter). Return the list of combinations in any order.

DSA Pattern Breakdown

DSA Pattern Breakdown

"Asteroid Mining Combinations"

medium

WHY DOES IT MATTER?

Backtracking is essential for problems where you need to explore all possible solutions or combinations, especially when the solution space is large and can be pruned. It allows you to systematically build candidate solutions and abandon them as soon as they are determined to be invalid, saving significant computation time compared to brute-force methods.

OPTIMIZATION CHALLENGE

The key insight is sorting the array and skipping duplicate values at the same recursion depth. By sorting, duplicates are adjacent, and by skipping them when they are not the first occurrence at that level, you ensure that each distinct combination is generated only once, reducing the effective branching factor and avoiding redundant work.

REAL-WORLD CONNECTION

This pattern is analogous to constraint satisfaction problems in logistics, such as finding all valid routes for a delivery truck that must visit a set of locations exactly once while staying within a fuel budget. Each decision to visit a location is a branch in the search tree, and backtracking occurs when a route exceeds the fuel limit or violates other constraints.

In an interview, clearly articulate the difference between 'skipping duplicates' and 'using duplicates'. Emphasize that you sort the array first and then, in the loop at each recursion level, you skip elements that are equal to the previous element if the previous element was not chosen in the current path. This demonstrates a deep understanding of the backtracking state and how to manage it efficiently.

COMPLEXITY AT A GLANCE

⏱ Time:O(2^n)
💾 Space:O(n)

Core Theory — Why This Approach?

The problem of finding distinct combinations that sum to a target is a classic application of backtracking, specifically the 'Combination Sum II' variant where each element can be used at most once. The naive approach of generating all subsets and filtering by sum results in exponential time complexity O(2^n), which is infeasible for large inputs. The core challenge lies in avoiding duplicate combinations when the input array contains duplicate values. Without proper pruning, the algorithm will generate identical combinations in different orders or from different indices of duplicate values, leading to redundant computation and incorrect output if not deduplicated.

Interview Questions on This Problem

Q1How would you modify this solution if the target sum could be negative or if the array contained negative numbers?

If negative numbers are allowed, the standard pruning technique (stopping when the current sum exceeds the target) no longer applies because adding a negative number could reduce the sum back to the target. In this case, the backtracking must explore all possibilities without early termination based on sum magnitude, potentially increasing the time complexity to O(2^n) in the worst case. However, the logic for handling duplicates remains the same: sort the array and skip duplicates at the same recursion depth to ensure distinct combinations.

Q2What is the difference between this problem and 'Combination Sum' (where elements can be reused)?

In 'Combination Sum', elements can be reused, so after choosing an element at index i, the next recursive call starts from index i (allowing the same element again). In this problem ('Combination Sum II'), each element can be used at most once, so the next recursive call must start from index i + 1. Additionally, this problem requires handling duplicate values in the input array by skipping them at the same recursion level to avoid duplicate combinations, whereas 'Combination Sum' typically assumes unique elements or does not require deduplication of combinations if elements are unique.

Q3How can you optimize the space complexity of this solution?

The space complexity is primarily determined by the recursion stack depth, which is O(n) in the worst case, and the storage for the result combinations. To optimize, you can use an iterative approach with an explicit stack to manage the backtracking state, though this often increases code complexity. More practically, you can minimize the overhead of copying the current combination by using a single list and adding/removing elements as you backtrack, rather than creating new lists at each recursive step. This reduces the constant factor in space usage.

Examples

Example 1

Input

{"nums":[2,3,5,7],"target":7}

Output

[[2,5],[7]]

Explanation: The array contains 2,3,5,7. Combinations that sum to 7 are: 2+5=7 and the single element 7. No other subset reaches 7, and each element is used at most once, so the result is [[2,5],[7]].

Example 2

Input

{"nums":[10,1,2,7,6,1,5],"target":8}

Output

[[1,1,6],[1,2,5],[1,7],[2,6]]

Explanation: After sorting the array we have [1,1,2,5,6,7,10]. Valid subsets that sum to 8 are: 1+1+6, 1+2+5, 1+7, and 2+6. Each uses elements no more times than they appear, and all are unique, giving the four combinations listed.

Example 3

Input

{"nums":[2,4,6,8],"target":8}

Output

[[2,6],[8]]

Explanation: Possible subsets are 2+6=8 and the single element 8. The pair 4+4 is invalid because 4 appears only once in the input. Hence the result is [[2,6],[8]].

Constraints

  • 1 <= nums.length <= 40
  • -100 <= nums[i] <= 100
  • -1000 <= target <= 1000
  • All numbers are integers

Optimal Approach & Strategy

Sort the array and use backtracking to explore combinations, skipping duplicate elements at the same recursion depth to ensure distinct combinations. Prune the search space by stopping recursion when the current sum exceeds the target.

Brute Force Approach

Generate all possible subsets of the array and check if the sum of each subset equals the target. Use a set to store the subsets to avoid duplicates, then convert the set to a list of lists.

Verified Code Solutions

JavaScript Solution
Time: O(2^n)
function combinationSum2(nums, target) {
    nums.sort((a,b)=>a-b);
    const res=[];
    const path=[];
    function backtrack(start, remain){
        if(remain===0){
            res.push([...path]);
            return;
        }
        for(let i=start;i<nums.length;i++){
            if(i>start && nums[i]===nums[i-1]) continue; // skip dup
            if(nums[i]>remain) break;
            path.push(nums[i]);
            backtrack(i+1, remain-nums[i]);
            path.pop();
        }
    }
    backtrack(0,target);
    return res;
}

// Driver (same as template)
const readline = require('readline');
const rl = readline.createInterface({input:process.stdin,output:process.stdout});
let lines=[];
rl.on('line', line=>{lines.push(line.trim()); if(lines.length===3) rl.close();});
rl.on('close',()=>{
    const n = parseInt(lines[0]);
    const nums = lines[1].split(/\s+/).map(Number);
    const target = parseInt(lines[2]);
    const res = combinationSum2(nums,target);
    res.forEach(comb=> console.log(comb.join(' ')));
});

Asked in Top Tech Interviews

Microsoft

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.