Alkesh

LeetCode - Combination Sum III

Problem statement

Find all valid combinations of k numbers that sum up to n such that the following conditions are true:

  • Only numbers 1 through 9 are 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.

Problem statement taken from: https://leetcode.com/problems/combination-sum-iii.

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 combination.

Constraints:

- 2 <= k <= 9
- 1 <= n <= 60

Explanation

Backtracking

The problem can be solved using the similar approach we used in our previous two blogs Combination Sum II and Combination Sum. In this problem, we are not given any input array instead, we need to use numbers from 1 to 9.

Let's check the algorithm to see how the solution works.

- initialize the result as a 2D array
  initialize current as an array

  // current = current list of elements in the array at the start it will be an empty array []
  // currentIndex = index, at start it will be 1.
  // sumTillNow = sum of the current elements in the array at the start it will be 0
  // numsAddedTillNow = count of numbers present in current array.
- call combinationSum2Util(result, current, currentIndex, sumTillNow, numsAddedTillNow, k, n)

- return result

// combinationSum3Util function
- if numsAddedTillNow == k && sumTillNow == n
  // append current to result
  - result.push_back(current)

- if numsAddedTillNow > k || sumTillNow == n
  - return

- loop for i = currentIndex; i <= 9; i++
  - sumTillNow = sumTillNow + i
  - current.push_back(i)
  - numsAddedTillNow = numsAddedTillNow + 1

  // call the function recursively
  - combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)

  - sumTillNow = sumTillNow - i
  - current.pop_back()
  - numsAddedTillNow = numsAddedTillNow - 1

Let's check our solutions in C++, Golang, and Javascript.

C++ solution

class Solution {
public:
    void combinationSum3Util(vector<vector<int>> &result, vector<int>& current, int currentIndex, int sumTillNow, int numsAddedTillNow, int k, int n) {
        if(numsAddedTillNow == k && sumTillNow == n) {
            result.push_back(current);
            return;
        }

        if(numsAddedTillNow > k || sumTillNow > n) {
            return;
        }

        for(int i = currentIndex; i <= 9; i++) {
            sumTillNow += i;
            current.push_back(i);
            numsAddedTillNow++;

            combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n);

            sumTillNow -= i;
            current.pop_back();
            numsAddedTillNow--;
        }
    }

    vector<vector<int>> combinationSum3(int k, int n) {
        vector<vector<int>> result;
        vector<int> current;

        combinationSum3Util(result, current, 1, 0, 0, k, n);

        return result;
    }
};

Golang solution

func combinationSum3Util(result *[][]int, current []int, currentIndex, sumTillNow, numsAddedTillNow, k, n int) {
    if numsAddedTillNow == k && sumTillNow == n {
        *result = append(*result, append([]int{}, current...))
        return
    }

    if numsAddedTillNow > k || sumTillNow > n {
        return
    }

    for i := currentIndex; i <= 9; i++ {
        sumTillNow += i
        current = append(current, i)
        numsAddedTillNow++

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)

        sumTillNow -= i
        current = current[:len(current) - 1]
        numsAddedTillNow--
    }
}

func combinationSum3(k int, n int) [][]int {
    result := make([][]int, 0)

    combinationSum3Util(&result, []int{}, 1, 0, 0, k, n)

    return result
}

Javascript solution

var combinationSum3 = function(k, n) {
    let result = [];

    const combinationSum3Util = (current, currentIndex, sumTillNow, numsAddedTillNow, k, n) => {
        if(numsAddedTillNow == k && sumTillNow == n) {
            result.push([...current]);
            return;
        }

        if(numsAddedTillNow > k || sumTillNow > n) {
           return;
        }

        for(let i = currentIndex; i <= 9; i++) {
            sumTillNow += i;
            current.push(i);
            numsAddedTillNow++;

            combinationSum3Util(current, i + 1, sumTillNow, numsAddedTillNow, k, n);

            sumTillNow -= i;
            current.pop();
            numsAddedTillNow--;
        }
    }

    combinationSum3Util([], 1, 0, 0, k, n);

    return result;
};

Let's dry run our algorithm for a few iterations and recursion.

Input: k = 3, n = 7

// combinationSum function
Step 1: vector<vector<int>> result
        vector<int> current

Step 2: combinationSum3Util(result, current, 1, 0, 0, k, n)

// combinationSum2Util function
Step 3: if numsAddedTillNow == k && sumTillNow == n
           0 == 3 && 0 == 7
           false

        if numsAddedTillNow > k || sumTillNow > n
           0 > 3 || 0 > 7
           false

        loop for i = currentIndex; i <= 9
        i = 1
        i <= 9
        true

        sumTillNow = sumTillNow + i
                   = 0 + 1
                   = 1

        current.push_back(i)
        current = [1]

        numsAddedTillNow = numsAddedTillNow + 1
                         = 0 + 1
                         = 1

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)
        combinationSum3Util([[]], [1], 1 + 1, 1, 1, 3, 7)
        combinationSum3Util([[]], [1], 2, 1, 1, 3, 7)

Step 4: if numsAddedTillNow == k && sumTillNow == n
           1 == 3 && 1 == 7
           false

        if numsAddedTillNow > k || sumTillNow > n
           1 > 3 || 1 > 7
           false

        loop for i = currentIndex; i <= 9
        i = 2
        i <= 9
        true

        sumTillNow = sumTillNow + i
                   = 1 + 2
                   = 3

        current.push_back(i)
        current.push_back(2)
        current = [1, 2]

        numsAddedTillNow = numsAddedTillNow + 1
                         = 1 + 1
                         = 2

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)
        combinationSum3Util([[]], [1, 2], 1 + 1, 3, 2, 3, 7)
        combinationSum3Util([[]], [1, 2], 2, 3, 2, 3, 7)

Step 5: if numsAddedTillNow == k && sumTillNow == n
           2 == 3 && 3 == 7
           false

        if numsAddedTillNow > k || sumTillNow > n
           2 > 3 || 3 > 7
           false

        loop for i = currentIndex; i <= 9
        i = 3
        i <= 9
        true

        sumTillNow = sumTillNow + i
                   = 3 + 3
                   = 6

        current.push_back(i)
        current.push_back(3)
        current = [1, 2, 3]

        numsAddedTillNow = numsAddedTillNow + 1
                         = 2 + 1
                         = 3

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)
        combinationSum3Util([[]], [1, 2, 3], 2 + 1, 6, 3, 3, 7)
        combinationSum3Util([[]], [1, 2, 3], 3, 6, 3, 3, 7)

Step 6: if numsAddedTillNow == k && sumTillNow == n
           3 == 3 && 3 == 7
           false

        if numsAddedTillNow > k || sumTillNow > n
           3 > 3 || 6 > 7
           false

        loop for i = currentIndex; i <= 9
        i = 4
        i <= 9
        true

        sumTillNow = sumTillNow + i
                   = 6 + 4
                   = 10

        current.push_back(i)
        current.push_back(4)
        current = [1, 2, 3, 4]

        numsAddedTillNow = numsAddedTillNow + 1
                         = 3 + 1
                         = 4

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)
        combinationSum3Util([[]], [1, 2, 3, 4], 3 + 1, 10, 4, 3, 7)
        combinationSum3Util([[]], [1, 2, 3, 4], 4, 10, 4, 3, 7)

Step 7: if numsAddedTillNow == k && sumTillNow == n
           4 == 3 && 10 == 7
           false

        if numsAddedTillNow > k || sumTillNow > n
           4 > 3 || 10 > 7
           true

           return

        we backtrack to step 6

Step 8: combinationSum3Util([[]], [1, 2, 3, 4], 4, 10, 4, 3, 7)
        sumTillNow = sumTillNow - i
                   = 10 - 4
                   = 6

        current.pop_back()
        current = [1, 2, 3]

        numsAddedTillNow = numsAddedTillNow - 1
                         = 4 - 1
                         = 3

        i++
        i = 5

        loop for i = currentIndex; i <= 9
        i = 5
        i <= 9
        true

        sumTillNow = sumTillNow + i
                   = 6 + 5
                   = 11

        current.push_back(i)
        current.push_back(5)
        current = [1, 2, 3, 5]

        numsAddedTillNow = numsAddedTillNow + 1
                         = 3 + 1
                         = 4

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)
        combinationSum3Util([[]], [1, 2, 3, 5], 3 + 1, 11, 4, 3, 7)
        combinationSum3Util([[]], [1, 2, 3, 5], 4, 11, 4, 3, 7)

Step 9: if numsAddedTillNow == k && sumTillNow == n
           4 == 3 && 11 == 7
           false

        if numsAddedTillNow > k || sumTillNow > n
           4 > 3 || 11 > 7
           true

           return

        we backtrack to step 8 and this gets repeated till i or currentIndex is 9.
        From all these steps, we backtrack to step 6.

Step 10...11...17:

Step 18: combinationSum3Util([[]], [1, 2, 3], 3, 6, 3, 3, 7)
        sumTillNow = sumTillNow - i
                   = 6 - 3
                   = 3

        current.pop_back()
        current = [1, 2]

        numsAddedTillNow = numsAddedTillNow - 1
                         = 3 - 1
                         = 2

        i++
        i = 4

        loop for i = currentIndex; i <= 9
        i = 4
        i <= 9
        true

        sumTillNow = sumTillNow + i
                   = 3 + 4
                   = 7

        current.push_back(i)
        current.push_back(4)
        current = [1, 2, 4]

        numsAddedTillNow = numsAddedTillNow + 1
                         = 2 + 1
                         = 3

        combinationSum3Util(result, current, i + 1, sumTillNow, numsAddedTillNow, k, n)
        combinationSum3Util([[]], [1, 2, 4], 2 + 1, 7, 3, 3, 7)
        combinationSum3Util([[]], [1, 2, 4], 3, 7, 3, 3, 7)

Step 19: if numsAddedTillNow == k && sumTillNow == n
            3 == 3 && 7 == 7
            true

            result.push_back(current)
            result = [[1, 2, 4]]

            return

The backtracking continues till we reach currentIndex = 10.
We return the answer as [[1, 2, 4]].
Share this post!