040 Combination Sum II[M]

1 题目描述

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

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

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

难度:Medium

2 题目样例

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, 
A solution set is: 
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

3 题意分析

有一个正整数集合C和一个正整数目标T。现从C中选出一些数,使其累加和恰好等于T(C中的每个数都只能取一次!!),求所有不同的取数方案。

注意正整数集合中可能存在重复的数字,而这些数字用于组合的时候,会产生重复的排列。题目要求相同的排列只出现一次。

4 思路分析

这个问题和我之前见到的NYOJ上的那道题更像了……依然可以使用深搜来解决。

本题在深搜过程中,需要注意如何避免组合重复,因为不能重复,所以要跳过一样的数字。

代码实现如下

class Solution 

{
    
public:
    
    vector<int> temp;
    
    vector<vector<int> > result;
    
    void DFS(vector<int> &candidates, vector<int> &temp, size_t index, int target)
        
    {
        if (target == 0)
            
        {
            result.push_back(temp);
            
            return;
        }

        else
            
        {
            int prev = -1;
            
            for (size_t i = index; i < candidates.size(); i++)
                
            {
                if (prev == candidates[i])
                    
                    continue;
                
                if (candidates[i] > target)
                    
                    return;
                
                prev = candidates[i];

                temp.push_back(candidates[i]);
                
                DFS(candidates, temp, i+1, target - candidates[i]);
                
                temp.pop_back();
            }
        }
    }
    
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
    
    {
        sort(candidates.begin(), candidates.end());
        
        DFS(candidates, temp, 0, target);
        
        return result;
    }
};

我们可以看到,本题的代码和上一题的代码极其的相似,下面就来谈谈是怎么对区别之处进行处理的。(主函数中的去重被删除掉的原因自然是不必说的,毕竟题意都改变了。)

我们可以看到,在DFS函数中我声明了一个初始化为-1(因为集合C中的所有数字都是正数)的变量prev,并在之后进行了如下的操作:

prev = candidates[i];

                temp.push_back(candidates[i]);
                
                DFS(candidates, temp, i+1, target - candidates[i]);
                
                temp.pop_back();

由于题意,我们在对数组进行排序后,相同的数字每次只能使用一个,这段代码的作用就是如此:

由于数组中的元素可能有重复,所以我上述代码只需判断上一次循环过程中是否选择到了candidates[i]。如果是则跳过选择下一个candidates元素,直到下标到达比prev大的元素,选择该元素进行下一轮递归(因为数组是按照由小到大的顺序进行排序之后再处理的)。

5 后记

Combination Sum系列问题(后边还有一道III)是很受大家欢迎的问题。通过看题干信息中的like/dislike就能看出大家对于这个系列的问题还是很买账的…

三道题目各有各的特点,我们可以在比较中做一做这三道题,看哪些代码的细微改动可以迎合题目要求,从而获得进步。

    原文作者:Lolita
    原文地址: https://zhuanlan.zhihu.com/p/34258953
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞