子集生成(递归或二进制)
问题描述如下:
给一个集合,需要得到该集合的所有子集(不考虑空集)。
如 { A, B } => { A } { B } { A, B }
分析:
该类问题都需要遍历所有可能的结果,因此可以使用循环递归的方法来做。
但也可以使用比较巧妙的一种方式来做,联系二进制。
① 循环递归:每个元素都有选与不选两种状态,使用二叉树表示如下:
n 层的每个元素都可以通过 n-1 层的元素通过 ”新增“ 或 ”保留“ 得到。
参考代码:
// arr为原始集合 n为原始集合中的元素个数 current为当前处理集合元素的索引
void getSet(char *arr, int n, int current){
for(set<string>::iterator it = pre.begin(); it != pre.end(); it++){
ans.insert(*it+arr[current]); // 选
ans.insert(*it); // 不选
}
current++;
if(current == n) return;
else{
pre = ans;
ans.clear();
}
getSet(arr, n, current);
}
② 二进制:在二进制中,只有 2 种状态:0和1,而我们集合中求子集的时候每个元素也只有两个状态,
因此这两者之间可以对应起来,用 0 来表示不选,用 1 来表示选取。
故 { A, B, C } 可以表示为 111,∅ 表示为 000,所有的可能组合都在 000 ~ 111 中,
只要遍历一遍就可以得到所有的组合。
(这个做法相当经典, 有很多问题都可以用这样的方法解决)
参考代码:
// 二进制 经典做法
void getSet(char *arr, int n){
int maxValue = pow(2, n);
for(int i = maxValue-1; i > 0; i--){
string str = "";
for(int j = 0; j < n; j++){
// 查看二进制表示中第j位的数字是否为1
if((i>>j)%2 == 1){
str += arr[j];
}
}
ans.insert(str);
}
}
【END】感谢观看