77. 组合/78.子集/90. 子集 II

版权声明:只要梦想一天,只要梦想存在一天,就可以改变自己的处境。 https://blog.csdn.net/dongyanwen6036/article/details/86524303

之前的全排列系列是有细节区别的,一直不理解。

  • 1.dfs(nums,res,out, i + 1);强调的是下一个状态选或不选
  • 2.dfs(nums,res,out, start + 1);强调的是下一个子集解
    全排列系列
77. 组合

输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

在这里插入图片描述

 class Solution {
 public:
	 void help(vector<vector<int>>&res, vector<int>&out, int n, int k, int level)
	 {
		 if (out.size() == k) { res.push_back(out); return; }
		 for (int i = level; i <= n; i++)
		 {
			 out.push_back(i);
			 help(res, out, n, k, i + 1);
			 out.pop_back();
		 }
	 }
	 vector<vector<int>> combine(int n, int k) {
		 vector<vector<int>>res;
		 vector<int>out;
		 help(res,out,n,k,1);
         return res;
	 }
 };

78.子集

例如:nums=[1,2,3]
res:[[],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]]

分析:由于原集合每一个数字只有两种状态,要么存在,要么不存在,那么在构造子集时就有选择和不选择两种情况,所以可以构造一棵二叉树,左子树表示选择该层处理的节点,右子树表示不选择,最终的叶节点就是所有子集合,树的结构如下:

                        []        
                   /          \        
                  /            \     
                 /              \
              [1]                []
           /       \           /    \
          /         \         /      \        
       [1 2]       [1]       [2]     []
      /     \     /   \     /   \    / \
  [1 2 3] [1 2] [1 3] [1] [2 3] [2] [3] []
class Solution {
 public:
	 //回溯法,一系列全排列
	 void dfs(vector<int>& nums,vector<vector<int>>&res, vector<int>&out, int start)
	 {
		 res.push_back(out);//每个状态都压进去
		 for (int i = start; i < nums.size(); i++)
		 {
			 out.push_back(nums[i]);
			 dfs(nums,res,out, i + 1);
			 out.pop_back();
		 }
	 }
	 vector<vector<int>> subsets(vector<int>& nums) {
		 vector<vector<int>>res;
		 vector<int>out;          
		 dfs(nums,res,out,0);
		 return res;
	 }

 };
static const auto speedup=[](){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    return nullptr;
}();

假设nums[1,2,3]如果是写成dfs(nums,res,out, start + 1);结果是

[[], [1], [1, 2], [1, 2, 3], [1, 3], [1, 3, 3], [2], [2, 2], [2, 2, 3], [2, 3], [2, 3, 3], [3], [3, 2], [3, 2, 3], [3, 3], [3, 3, 3]]

出现[2,2]原因是i已经到了1,但是还要递归start+1即1.

90. 子集 II

利用上面的代码nums=[1,2,2],
其结果是[[],[1],[1,2],[1,2,2],[1,2],[2],[2,2],[2]]
那么我需要剪枝:

                        []        
                   /          \        
                  /            \     
                 /              \
              [1]                []
           /       \           /    \
          /         \         /      \        
       [1 2]       [1]       [2]     []
      /     \     /   \     /   \    / \
  [1 2 2] [1 2]  X   [1]  [2 2] [2] X  []

代码只需在原有的基础上增加一句话,while (S[i] == S[i + 1]) ++i; 这句话的作用是跳过树中为X的叶节点,因为它们是重复的子集,应被抛弃。代码如下:

class Solution {
public:
    
	 void dfs(vector<int>& nums,vector<vector<int>>&res, vector<int>&out, int start)
	 {
         			 
		 res.push_back(out);
		 for (int i = start; i < nums.size(); i++)
		 {
			 out.push_back(nums[i]);
			 dfs(nums,res,out, i + 1);
			 out.pop_back();
             //while(i!=0&&nums[i]==nums[i-1])i++;//已经添加了
             while((i!=nums.size()-1)&&nums[i]==nums[i+1])i++;
		 }
	 }
	 vector<vector<int>> subsetsWithDup(vector<int>& nums) {
		 vector<vector<int>>res;
		 vector<int>out;
         sort(nums.begin(),nums.end());
		 dfs(nums,res,out,0);
		 return res;
	 }
    

 };


写成这样更快:
不要后加入res,先加

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int>> res ;
        int len = nums.size();
        sort(nums.begin(),nums.end());
        vector<int> temp; 
        res.push_back(temp);
        fun(nums,0,temp,res);
        return res;
    }
    void fun(vector<int>& nums,int i,vector<int>& temp,vector<vector<int>> &res){
        
        for(int j = i;j<nums.size();j++){
            if(j>i&&nums[j]==nums[j-1])
                continue;
            temp.push_back(nums[j]);
            res.push_back(temp);
            fun(nums,j+1,temp,res);
            temp.pop_back();
        }
        return;
        
    }
};

[1]https://blog.csdn.net/u010500263/article/details/18435495
[2]https://www.cnblogs.com/grandyang/p/4332522.html

猜你喜欢

转载自blog.csdn.net/dongyanwen6036/article/details/86524303