class Solution { public: vector<vector<int> > combinationSum2(vector<int> &num, int target) { sort(num.begin(), num.end()); vector<vector<int> > tmp; vector<int> sel; dfs(num, 0, target, sel, tmp); return tmp; } void dfs(vector<int> &num, int pos, int target, vector<int>& sel, vector<vector<int> >& res) { if (target == 0) { res.push_back(sel); return; } if (pos >= num.size()) return; int cur = num[pos]; int dup = 0; int i = pos; while (++i < num.size() && num[i] == cur) dup++; int add = 0; for (i = 0; (i <= dup + 1) && add <= target; i++, add+=cur) { if (i != 0) { sel.push_back(cur); } dfs(num, pos + dup + 1, target - add, sel, res); } for (i = add/cur - 1; i>0; i--) sel.pop_back(); } };
类似01背包,不过这是求和,虽然说每个元素最多用一次,但是从例子中发现,所给的候选数时会有重复的。因为输出要求不能有重复,这时我们可以把多个重复的候选数看成是同一个数取[0, k]次(k为该数出现的次数)这和最初的CombinationSum中类似(只不过这里指定了每个元素出现的次数,而不是原先的可以取无限次),这相当于把重复的候选数压到了一个位置上,当我们在该位置做出取(一次性取n,n<=k)和不取两种选择后,后面再也不会对该数考虑相同的问题,这使得我们可以避免输出雷同解。