每日一题--求集合中的所有子集(递归非递归)(Google推荐面试书--Cracking the Coding Interview)

题目

  • 原文:
    Write a method that returns all subsets of a set.
  • 译文:
    写一个函数返回一个集合中的所有子集。

分析

  1. 非递归方法:
    对于一个长度为n的集合,它的子集共有2^n个,即n转化为二进制后n位选0或者1的组合。这样我们可以通过这些数每位的0、1分布来确定对应子集中是否有所在位的元素出现,具体代码见subset1。
  2. 递归方法:
    依次找集合中除去自己本身的子集,然后再在每个子集中加上自己形成新的子集。以{1,2,3}为例,先找除1以外的子集{ },{2},{3},{2,3},然后再加上包括自己本身在内的子集{1},{1,2},{1,3},{1,2,3},最终共有8个子集,具体代码见subset2。
    【这里求除1以外{2,3}的子集也一样,先求除去2以外的子集{ },{3},然后再加上包括2在内的子集{2},{2,3}】

代码

#include<iostream>
#include<vector>
using namespace std;

typedef vector<vector<int> > vvi;
typedef vector<int> vi;

void printsubset(vvi set) {
	for(int i = 0; i < set.size(); i++) {
		vi sub = set[i];
		cout << "{" ;
		for(int j = 0; j < sub.size(); j++) {
			cout << sub[j] << " ";
		}
		cout << "}" << endl;
	}
}

vvi subset1(int a[], int size) {
	int n = 1<<size;
	vvi set;
	for(int i = 0; i < n; i++) {
		int j = i;
		int idx = 0;	
		vi sub;
		while(j > 0) {
			if(j & 1) {
				sub.push_back(a[idx]);
			}
			j >>= 1;
			idx++;
		}
		set.push_back(sub);
	}
	return set;
}

//idx代表集合中从第idx位开始的子集 
vvi subset2(int a[], int idx, int size) {
	vvi set;
	
	//empty
	if (idx == size) {
		vi sub;
		set.push_back(sub);
		return set;
	}
	
	vvi rset = subset2(a, idx+1, size);
	for(int i = 0; i < rset.size(); i++) {
		vi sub = rset[i];	
		set.push_back(sub);
		sub.push_back(a[idx]);
		set.push_back(sub);
	}	
	return set;
}

int main() {
	int a[] = {1, 2, 3};
	int n = sizeof(a) / sizeof(int);
	vvi sub1 = subset1(a, n);
	vvi sub2 = subset2(a, 0, n);
	cout << "unrecursion method subset of {1, 2, 3} is: " << endl;
	printsubset(sub1);
	cout << "recursion method subset of {1, 2, 3} is: " << endl;
	printsubset(sub2);
}

结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_39860046/article/details/88093349