递归/回溯:Subsets II求子集(有重复元素)
生活随笔
收集整理的這篇文章主要介紹了
递归/回溯:Subsets II求子集(有重复元素)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
上一篇描述了針對(duì)數(shù)組中沒(méi)有重復(fù)元素進(jìn)行子集的求取過(guò)程遞歸/回溯:subsets求子集
但是當(dāng)出現(xiàn)如下數(shù)組時(shí):
例如: nums[] = [2, 1, 2, 2]
結(jié)果為: [[], [1], [1,2], [1,2,2], [1,2,2,2], [2], [2,2], [2,2,2]]
注意: [2,1,2]與[1,2,2]是重復(fù)的集合,則不滿足集合的要求。
思考:
同樣的遞歸回溯方式,即每一個(gè)元素在是否需要加入到集合中都會(huì)有兩種狀態(tài),存在或者不存在,這里加入的過(guò)程中可以對(duì)子集進(jìn)行篩選,如果之前的子集中已經(jīng)存在有相同的集合,則不需要加入;否則,再將篩選出來(lái)的子集加入到最終的集合中。
實(shí)現(xiàn)過(guò)程如下:
方法一,遞歸回溯實(shí)現(xiàn)
void generate(int i, std::vector<int> &num,std::vector<int> &item,std::vector<std::vector<int>> &result,std::set<std::vector<int>> &uniq_result) {if (i >= num.size()) {return;}item.push_back(num[i]);/*當(dāng)集合中沒(méi)有當(dāng)前item時(shí),則加入最終的子集中*/if (uniq_result.find(item) == uniq_result.end()) { result.push_back(item);uniq_result.insert(item);}generate(i + 1, num, item, result, uniq_result);item.pop_back();generate(i + 1, num, item, result, uniq_result);
}/*method1*/
std::vector<std::vector<int> > get_subsets(std::vector<int> &num) {std::vector<int> item;std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;//維護(hù)一個(gè)集合sort(num.begin(), num.end());//對(duì)初始序列進(jìn)行排序result.push_back(item);generate(0, num, item, result, uniq_result);return result;
}
方法二,位運(yùn)算實(shí)現(xiàn)
/*method2*/
std::vector<std::vector<int> > get_subsets2(std::vector<int> &num) {std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;int all_set = 1 << num.size();sort(num.begin(), num.end());for (int i = 0;i < all_set; ++i) {std::vector<int> item;for (int j = 0;j < num.size(); ++j) {if (i & (1 << j)) {item.push_back(num[j]);}}/*同樣使用集合來(lái)判斷是否需要加入最終的子集中*/if (uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}}return result;
}
測(cè)試代碼如下:
測(cè)試[2,1,2,2]
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>/*
Subsets II已知一組數(shù)(其中有重復(fù)元素),求這組數(shù)可以組成的所有子集。 結(jié)果中無(wú)重復(fù)的子集。
例如: nums[] = [2, 1, 2, 2]
結(jié)果為: [[], [1], [1,2], [1,2,2], [1,2,2,2], [2], [2,2], [2,2,2]]
注意: [2,1,2]與[1,2,2]是重復(fù)的集合
*/using namespace std;void generate(int i, std::vector<int> &num,std::vector<int> &item,std::vector<std::vector<int>> &result,std::set<std::vector<int>> &uniq_result) {if (i >= num.size()) {return;}item.push_back(num[i]);if (uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}generate(i + 1, num, item, result, uniq_result);item.pop_back();generate(i + 1, num, item, result, uniq_result);
}/*method1*/
std::vector<std::vector<int> > get_subsets(std::vector<int> &num) {std::vector<int> item;std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;sort(num.begin(), num.end());result.push_back(item);generate(0, num, item, result, uniq_result);return result;
}/*method2*/
std::vector<std::vector<int> > get_subsets2(std::vector<int> &num) {std::vector<std::vector<int>> result;std::set<std::vector<int> > uniq_result;int all_set = 1 << num.size();sort(num.begin(), num.end());for (int i = 0;i < all_set; ++i) {std::vector<int> item;for (int j = 0;j < num.size(); ++j) {if (i & (1 << j)) {item.push_back(num[j]);}}if (uniq_result.find(item) == uniq_result.end()) {result.push_back(item);uniq_result.insert(item);}}return result;
}int main(int argc, char const *argv[])
{std::vector<int> num;std::vector<int> item;std::vector<std::vector<int>> result;std::vector<std::vector<int>> result2;int tmp;int N;std::cin >> N;for (int i = 0;i < N; ++i) {std::cin >> tmp;num.push_back(tmp);}result = get_subsets(num);result2= get_subsets2(num);cout << "method1 " << endl;for (int i = 0;i < result.size(); ++i) {if (result[i].size() == 0) {cout << "[]";}for (int j = 0;j < result[i].size(); ++j) {std::cout << "[" << result[i][j] << "] ";}std::cout << std::endl;}cout << "method2 " << endl;for (int i = 0;i < result2.size(); ++i) {if (result2[i].size() == 0) {cout << "[]";}for (int j = 0;j < result2[i].size(); ++j) {std::cout << "[" << result2[i][j] << "] ";}std::cout << std::endl;} return 0;
}
輸出如下:
4
2 1 2 2
method1
[]
[1]
[1] [2]
[1] [2] [2]
[1] [2] [2] [2]
[2]
[2] [2]
[2] [2] [2]
method2
[]
[1]
[2]
[1] [2]
[2] [2]
[1] [2] [2]
[2] [2] [2]
[1] [2] [2] [2]
總結(jié)
以上是生活随笔為你收集整理的递归/回溯:Subsets II求子集(有重复元素)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: “大似落鹅毛”下一句是什么
- 下一篇: 对于"娶媳妇先看丈母娘"这话如何理解?[