216. Combination Sum III (M)

  1. Combination Sum III
    Medium

1519

61

Add to List

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

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. [1,2,1] is not valid because 1 is used twice.
Example 4:

Input: k = 3, n = 2
Output: []
Explanation: There are no valid combinations.
Example 5:

Input: k = 9, n = 45
Output: [[1,2,3,4,5,6,7,8,9]]
Explanation:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45
​​​​​​​There are no other valid combinations.

Constraints:

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


我的解法

class Solution {
public:
    vector> combinationSum3(int k, int n) {
        vector num_mask(9, true);
        vector> ret = recurr_search(k, n, num_mask);
        
        return ret;
    }
    
    vector> recurr_search(int k, int n, vector& num_mask) {
        vector> ret;
        
        if (k <= 0) {
            ret = {{}};
        }
        else if (k == 1) {
            for (int i=0; i<9; ++i) {
                if (num_mask[i] == true and i+1 == n) {
                    ret.emplace_back(vector{i+1});
                }
            }
        }
        else {
            vector num_mask_ = num_mask;
            for (int i=0; i<9; ++i) {
                if (num_mask[i] == true) {
                    num_mask[i] = false;
                    for (const auto& ret_from_recurr : recurr_search(k-1, n-i-1, num_mask)) {
                        vector temp{i+1};
                        temp.insert(temp.end(), ret_from_recurr.begin(), ret_from_recurr.end());
                        ret.emplace_back(temp);
                    }
                    num_mask[i] = true;
                }
                num_mask[i] = false; // mark 1
            }
            num_mask = num_mask_; // mark 2
        }
        
        return ret;
    }
};

Runtime: 4 ms, faster than 35.70% of C++ online submissions for Combination Sum III.
Memory Usage: 7.1 MB, less than 29.37% of C++ online submissions for Combination Sum III.

一开始考虑的是用unordered_set,但是想了想还是用vector比较方便,set没法O(1) random access。

然后concatenate两个vector一开始不知道,查了一下要用insert
https://stackoverflow.com/a/3177254/9556578

This is precisely what the member function std::vector::insert is for

std::vector AB = A;
AB.insert(AB.end(), B.begin(), B.end());

还有一个小bug,ret.emplace_back(vector{i+1});ret.push_back({i+1});可以通过,但是ret.emplace_back({i+1});不可以
https://stackoverflow.com/questions/51443319/why-is-emplace-back-failing-even-though-the-direct-constructor-works

还有2个问题是关于mask的修改,为了避免重复,必须在mark1的位置要加false,但是这样每次子循环结束都会导致num_mask被完全false掉,导致没有下一个子循环了,所以在mark2的位置要复原成原mask


https://zxi.mytechroad.com/blog/searching/leetcode-216-combination-sum-iii/

其实没必要用mask,搜索的时候因为没有重复,所以可以从上次搜到的数的后一个开始

// Author: Huahua
// Runtime: 0 ms
class Solution {
public:
    vector> combinationSum3(int k, int n) {
        vector> ans;
        vector cur;
        dfs(k, n, 1, cur, ans);
        return ans;
    }
private:
    // Use k numbers (>= s) to sum up to n
    void dfs(int k, int n, int s, 
             vector& cur, vector>& ans) {
        if (k == 0) {
            if (n == 0) ans.push_back(cur);
            return;
        }
        
        for (int i = s; i <= 9; ++i) {
            if (i > n) return;
            cur.push_back(i);
            dfs(k - 1, n - i, i + 1, cur, ans);
            cur.pop_back();
        }
    }
};

我默写的答案:

class Solution {
public:
    vector> combinationSum3(int k, int n) {
        vector> ans;
        vector curr;
        dfs(k, n, 0, curr, ans);
        
        return ans;
    }
    
    void dfs(int k, int n, int start, vector& curr, vector>& ans) {
        if (n < 0) return;
        if (n == 0 and k == 0) {
            ans.emplace_back(curr);
            return;
        }
            
        for (int i=start; i<9; ++i) {
            curr.emplace_back(i+1);
            dfs(k-1, n-i-1, i+1, curr, ans);
            curr.pop_back();
        }
    }
};

Runtime: 0 ms, faster than 100.00% of C++ online submissions for Combination Sum III.
Memory Usage: 6.8 MB, less than 58.74% of C++ online submissions for Combination Sum III.

注意,dfs里面的k n start都不能加引用,因为是k-1, n-i-1, i+1, 0都是rvalue
除非这么写:

class Solution {
public:
    vector> combinationSum3(int k, int n) {
        vector> ans;
        vector curr;
        dfs(k+0, n+0, 0, curr, ans);
        
        return ans;
    }
    
    void dfs(int&& k, int&& n, int&& start, vector& curr, vector>& ans) {
        if (n < 0) return;
        if (n == 0 and k == 0) {
            ans.emplace_back(curr);
            return;
        }
            
        for (int i=start; i<9; ++i) {
            curr.emplace_back(i+1);
            dfs(k-1, n-i-1, i+1, curr, ans);
            curr.pop_back();
        }
    }
};

Runtime: 0 ms, faster than 100.00% of C++ online submissions for Combination Sum III.
Memory Usage: 6.5 MB, less than 91.93% of C++ online submissions for Combination Sum III.

你可能感兴趣的:(216. Combination Sum III (M))