Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 40. Combination Sum II #40

Open
grandyang opened this issue May 30, 2019 · 0 comments
Open

[LeetCode] 40. Combination Sum II #40

grandyang opened this issue May 30, 2019 · 0 comments

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019


请点击下方图片观看讲解视频
Click below image to watch YouTube Video
Video

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sum to target.

Each number in candidates may only be used once in the combination.

Note: The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8
Output: 
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

Example 2:

Input: candidates = [2,5,2,1,2], target = 5
Output: 
[
[1,2,2],
[5]
]

Constraints:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

这道题跟之前那道 Combination Sum 本质没有区别,只需要改动一点点即可,之前那道题给定数组中的数字可以重复使用,而这道题不能重复使用,只需要在之前的基础上修改几个地方即可,首先要给数组排个序,然后在递归的 for 循环里加上 if (i > start && num[i] == num[i - 1]) continue; 这样可以防止 res 中出现重复项,最后就在递归调用 dfs 里面的参数换成 i+1,这样就不会重复使用数组中的数字了,代码如下:

解法一:

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> res;
        vector<int> cur;
        sort(candidates.begin(), candidates.end());
        dfs(candidates, target, 0, cur, res);
        return res;
    }
    void dfs(vector<int>& candidates, int target, int start, vector<int>& cur, vector<vector<int>>& res) {
        if (target < 0) return;
        if (target == 0) { res.push_back(cur); return; }
        for (int i = start; i < candidates.size(); ++i) {
            if (i > start && candidates[i] == candidates[i - 1]) continue;
            cur.push_back(candidates[i]);
            dfs(candidates, target - candidates[i], i + 1, cur, res);
            cur.pop_back();
        }
    }
};

对于之前的解法二可以通过稍微改动而适用于这里,同样的在处理当前数字 candidates[i] 时,和之前的数字比较,要跳过重复数字。其次就是在为下次递归创建新数组时,不能包括当前的数字,这样的话才能保证不重复使用数字,参见代码如下:

解法二:

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> res;
        sort(candidates.begin(), candidates.end());
        for (int i = 0; i < candidates.size(); ++i) {
            if (candidates[i] > target) break;
            if (candidates[i] == target) { res.push_back({candidates[i]}); break; }
            if (i > 0 && candidates[i] == candidates[i - 1]) continue;
            vector<int> vec = vector<int>(candidates.begin() + i + 1, candidates.end());
            vector<vector<int>> tmp = combinationSum2(vec, target - candidates[i]);
            for (auto a : tmp) {
                a.insert(a.begin(), candidates[i]);
                res.push_back(a);
            }
        }
        return res;
    }
};

对于 DP 解法来说,改变就比较大了,甚至可以说是完全不同的解法也不为过,这种原数组中有重复数字,且每个数字只能使用一次的要求,不太适合用 DP 来做,但也可以强行使用 DP 来做,只不过稍微有点麻烦。

解法三:

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<vector<int>>> dp(target + 1);
        dp[0].resize(1);
        map<int, int> numCnt;
        for (int num : candidates) {
            ++numCnt[num];
        }
        for (auto a : numCnt) {
            int num = a.first, cnt = a.second;
            for (int i = target - num; i >= 0; --i) {
                for (auto v : dp[i]) {
                    int sum = i;
                    for (int k = 0; k < cnt && sum <= target - num; ++k) {
                        sum += num;
                        v.push_back(num);
                        dp[sum].push_back(v);
                    }
                }
            }
        }
        return dp[target];
    }
};

Github 同步地址:

#40

类似题目:

Combination Sum III

Combination Sum

参考资料:

https://leetcode.com/problems/combination-sum-ii/

https://leetcode.com/problems/combination-sum-ii/discuss/16861/Java-solution-using-dfs-easy-understand

https://leetcode.com/problems/combination-sum-ii/discuss/16878/Combination-Sum-I-II-and-III-Java-solution-(see-the-similarities-yourself)

LeetCode All in One 题目讲解汇总(持续更新中...)

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)

知识星球 喜欢请点赞,疼爱请打赏❤️~.~

微信打赏

|

Venmo 打赏


---|---

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant