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 dfs
methods.
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 0
sum 1
? For an n
array of numbers, there are two choices for each digit, and the total is (2^n)
possible, so we can iterate through 0~(2^n)-1
the 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 set
the 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 2
and the second one 2
is indistinguishable, they are equivalent. Therefore, we thought of using one map
to 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 2
as the same, and there is no difference. When searching for 2
this 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.