排列 / 组合 / 子集合

1.数组中元素的全排列

 

  题目链接:https://www.acwing.com/problem/content/96/ (算法竞赛进阶指南)

       https://www.lintcode.com/problem/permutations-ii/description/  (Lintcode)

  思路:

       1.对数组进行排序

       2.枚举每一个位置上选择什么数字

       3.跳过重复的元素

  代码:

      

class Solution {
public:

    vector<int> nums;
    vector<vector<int>> res; 
    vector<int> temp;
    int n;
    vector<bool> st;
    
    void calc(int k)
    {
        if(k == n + 1)
        {
            res.push_back(temp);
            return;
        }
        
        for(int i = 0; i < n; i++)
        {
            if(st[i] == true) continue;
            st[i] = true;
            temp.push_back(nums[i]);
            calc(k + 1);
            st[i] = false;
            temp.pop_back();
            while(i + 1 < n && nums[i + 1] ==  nums[i]) i++;
        }
        
    }
    
    vector<vector<int>> permuteUnique(vector<int> &s) {
        n = s.size();
        nums = s;
        sort(nums.begin(), nums.end());
        st = vector<bool>(n, false);
        calc(1);
        return res;
    }
};

 

2.数组中元素的组合

 

  题目链接:https://www.acwing.com/problem/content/description/95/ (算法竞赛进阶指南)

  思路:枚举每个数字选择或者不选择, 二进制存储选择了哪些数字

  代码:

    

#include <bits/stdc++.h>
using namespace std;

int n, m;
void dfs(int u, int sum, int state)
{
    if(sum + n - u < m) return;
    if(sum == m)
    {
         for(int i = 0; i < n; i++)
            if(state >> i & 1)
                cout << i + 1 << " ";
        cout << endl;
        return;       
    }
    
    if(u == n) return;
    
    dfs(u + 1, sum + 1, state + (1 << u));
    dfs(u + 1, sum,  state);

}

int main()
{
    cin >> n >> m;
    
    //第几个数, 选了几个数,选了什么数字
    dfs(0, 0, 0);
    return 0;
}

 

 

3.集合的子集

 

  题目链接:https://www.acwing.com/problem/content/94/ (算法竞赛进阶指南)

        https://www.lintcode.com/problem/subsets-ii/description (LintCode)

   思路:枚举每个数字选或者不选,直到最后一个位置。遇到连续的相同元素跳过

   代码:

class Solution {
public:
    /**
     * @param nums: A set of numbers.
     * @return: A list of lists. All valid subsets.
     */
     
    vector<vector<int> > res;
    vector<int> nums;
    vector<int> temp;
    int n;
     
    void dfs(int a, int b)
    {
        if(a == n)
        {
            for(int i = 0; i < n; i++)
            {
                if(b >> i & 1)
                {
                    temp.push_back(nums[i]);
                }
            }
            res.push_back(temp);
            temp.clear();
            return;
        }
        

        dfs(a + 1, b + (1 << a));  
            
        while(a + 1 < n && nums[a] == nums[a + 1]) a++;
        dfs(a + 1, b);
    }
    
    vector<vector<int>> subsetsWithDup(vector<int> &s) {
        // write your code here
        n = s.size();
        nums = s;
        sort(nums.begin(), nums.end());
        dfs(0, 0);
        return res;
    }
};

 

4.上升子序列

 

  题目链接:https://leetcode.com/problems/increasing-subsequences/ (Leetcode)

   思路:不能打乱原数组的顺序,因此不能通过排序进行去重。

     1.二进制枚举每一种选择的可能,将不符合要求的方案直接删除

     2.利用set进行去重

   代码:

 

class Solution {
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        int size = nums.size();
        set<vector<int>> f;
        vector<vector<int> > res;
        for(int i = 0; i < (1 << size); i++)
        {
            vector<int> temp;
            for(int j = 0; j < size; j++)
            {
                if(i & (1 << j))
                {
                    temp.push_back(nums[j]);
                }
            }
            
            for(int j = 1; j < temp.size(); j++)
            {
                if(temp[j] < temp[j - 1])
                {
                    temp.clear();
                    break;
                }
            }
            
            if(temp.size() >= 2)
                if(f.find(temp) == f.end())
                {
                    f.insert(temp);   
                    res.push_back(temp);
                }        
        }
        
      return res;   
    }
};

 

 

 

 

        

posted @ 2020-08-07 14:49  锤子科技未来产品经理  阅读(123)  评论(0)    收藏  举报