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 (alkeshghorpade.me/post/leetcode-combination..) 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]].

Did you find this article valuable?

Support Alkesh Ghorpade by becoming a sponsor. Any amount is appreciated!