Leetcode 78&90. Subsets I & II [Generation summary of permutations and combinations]

78. Subsets

Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:

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

topic

This is a very typical depth-first search problem. For each bit, you can choose or not, and then perform a recursive search to build a search tree. Note: The numbers in this question are not repeated.

Solution one

Recursive search construction using traditional dfsmethods.
code show as below:

class Solution {
public:
    vector<vector<int> > vvi;   
    vector<int> vi;
    void solve(vector<int> &s, int idx){
        if (idx == s.size()){                       
            vvi.push_back(vi);
            return;
        }
        solve(s, idx + 1);
        vi.push_back(s[idx]);
        solve(s, idx + 1);
        vi.pop_back();
    }
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        vvi.clear();
        vi.clear();
        solve(S, 0);
        return vvi;
    }
};

Solution two

Considering this recursive operation carefully, in fact, there are two possibilities for each bit, to choose or not to choose, isn't that the binary 0sum 1? For an narray of numbers, there are two choices for each digit, and the total is (2^n)possible, so we can iterate through 0~(2^n)-1the numbers from, and the binary representation of each number represents a choice, and then we take one digit at a time, The entire composition can be constructed. This avoids recursive builds.
code show as below:

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        int cnt = pow(2, nums.size());
        vector<vector<int> > vvi;
        for (int i = 0; i < cnt; ++i)
        {
            vector<int> vi;
            for (int j = 0; j < nums.size(); ++j)
            {
            // 选一位
                int tmp = 0x01 << j;
                if (tmp & i)
                {
                    vi.push_back(nums[j]);
                }
            }
            vvi.push_back(vi);
        }
        return vvi;
    }
};

90. Subsets II

topic

Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
For example,
If nums =[1,2,2], a solution is:

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

Topic Analysis

The difference between this question and the above is that there will be repeated elements. If the method of the previous question is directly applied, there will be repeated answers, because the same number in two different positions will be considered different when it is generated. What to do, of course, there are still ways~

Solution one

Of course, the easiest way is to first generate the combination according to the original method, and then put the results into setthe middle for de-duplication. Note: here you need to sort first, otherwise there may be problems in the judgment. Of course such a method feels ashamed == the
code is as follows:

class Solution {
public:
    vector<vector<int> > vvi;
    set<vector<int> > svi;
    vector<int> vi;
    void solve(vector<int> &s, int idx){
        if (idx == s.size()){               
            svi.insert(vi);
            return;
        }
        solve(s, idx + 1);
        vi.push_back(s[idx]);
        solve(s, idx + 1);
        vi.pop_back();
    }
    vector<vector<int> > subsetsWithDup(vector<int> &S) {
        svi.clear();
        vvi.clear();
        // 排序
        sort(S.begin(), S.end());       
        solve(S, 0);
        for (set<vector<int> >::iterator it = svi.begin(); it != svi.end(); it++){
            vvi.push_back(*it);
        }
        return vvi;
    }
};

Solution two

Because of the repetition, assuming our input sequence is [1,2,2], the goal of our program design is to choose the first one 2and the second one 2is indistinguishable, they are equivalent. Therefore, we thought of using one mapto store the number of each element. We only choose according to the number, not according to the position of the element, so we treat the different positions 2as the same, and there is no difference. When searching for 2this node, we have three choices, choose one, choose two, or choose none.
code show as below:

class Solution {
public:
    void solve(map<int, int> &mp, int idx, vector<vector<int>>&vvi, vector<int> &vi, vector<int>& nums)
    {
        if (idx == nums.size())
        {
            vvi.push_back(vi);
            return;
        }
        for (int i = 0; i <= mp[nums[idx]]; ++i)
        {
            for (int j = 0; j < i; ++j)
                vi.push_back(nums[idx]);
            solve(mp, idx+1, vvi, vi, nums);
            for (int j = 0; j < i; ++j)
                vi.pop_back();
        }    
    }

    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        map<int,int> mp;
        vector<int> numbers;
        for (const auto &i : nums)
            mp[i]++;
        for (auto it = mp.begin(); it != mp.end(); ++it)
            numbers.push_back(it->first);
        vector<vector<int> > vvi;
        vector<int> vi;
        solve(mp, 0, vvi, vi, numbers);
        return vvi;
    }
};

Permutation Generation and Combination Generation Analysis

The generation of the combination is regardless of the order of the elements, and the generation of the arrangement is the same group of elements, and different arrangements are regarded as different arrangements. Therefore, when generating combinations, we need to control an order, because we do not need this order, as long as they have the same elements, the result is the same. But when the permutation is generated, we need to search all the next nodes on each searched node, so that we can traverse all the nodes. The generation of permutations and combinations can essentially be regarded as the generation of search trees under certain conditions.
Given below is the code to generate permutations of sequences containing repeating elements, again using a hash to count. If there is no repeating sequence, just use a boolean array directly.
code show as below:

void solve(map<int, int> &mp, int idx, vector<vector<int>>&vvi, vector<int> &vi, vector<int>& nums,int size)
{
    if (idx == size)
    {
        vvi.push_back(vi);
        return;
    }
    for (int i = 0;i< nums.size(); ++i)
    {
        if (mp[nums[i]] > 0)
        {           
            vi.push_back(nums[i]);
            --mp[nums[i]];
            solve(mp, idx + 1, vvi, vi, nums, size);
            ++mp[nums[i]];
            vi.pop_back();
        }
    }
}

vector<vector<int>> subsetsWithDup(vector<int>& nums) {
    map<int,int> mp;
    vector<int> numbers;
    for (const auto &i : nums)
        mp[i]++;
    for (auto it = mp.begin(); it != mp.end(); ++it)
        numbers.push_back(it->first);
    vector<vector<int> > vvi;
    vector<int> vi;
    int size = nums.size();
    solve(mp, 0, vvi, vi, numbers, size);
    return vvi;
}

Corrections are welcome.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325769169&siteId=291194637