LintCode笔记(11)—— 带重复元素的子集

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lhanchao/article/details/54629065

给定一个可能具有重复数字的列表,返回其所有可能的子集

 注意事项
  • 子集中的每个元素都是非降序的
  • 两个子集间的顺序是无关紧要的
  • 解集中不能包含重复子集
样例

如果 S = [1,2,2],一个可能的答案为:

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

与这道题相类似的题目同样也是求子集,不过限定集合中不包含重复的元素,但是这道题目不限定集合中是否有重复元素,因此这道题的答案同样可以应用到限制不包含重复元素的题目。对于这类题目,我只想到了一种使用非递归的解决方法。

首先我们知道有n个元素的集合,则它一共有2^n个子集(包括空集和它自身),那么对于有n个字符的集合,我们可以使用n位的二进制数标志该n个元素集合的哪些元素在它的子集中。

例如有3个元素的集合{1,2,3},一共有8个子集,则用3位的二进制数标志为:

00,001,010,011,100,101,110,111,其中若某位为1,则标志该位的元素在该子集中,则这8个二进制数对应的子集分别为 {},{3},{2},{2,3},{1},{1,3},{1,2},{1,2,3}。

而对于本题中的集合可能存在相同的元素的要求,我们可以在插入新得到的子集到结果集之前首先判断结果集中是否已经存在与该子集相等的子集,若存在则不插入,若不存在则直接插入。

实现代码如下:

#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>

using namespace std;

static bool sortByNum(int num1, int num2)
{
	return num1 < num2;
}

//把指定的int类型的数字转换为二进制字符串,存入binaryStr中
//binaryStr为已经定长的vector数组,初始化全部元素为0
void intToBinary(int num, vector<int>& binaryStr)
{
	int i = 0;
	while (num / 2 != 0)
	{
		binaryStr[binaryStr.size() - i - 1] = num % 2;
		num = num / 2;
		i++;
	}
	binaryStr[binaryStr.size() - i - 1] = num % 2;
}
/**
* @param S: A set of numbers.
* @return: A list of lists. All valid subsets.
*/
vector<vector<int> > subsets(vector<int> &nums)
{
	// write your code here
	vector<vector<int> > result;
	//一共有2^(nums.size())个子集
	for (int i = 0; i < pow(2,nums.size()); i++)
	{
		//二进制字符串数组,某元素为1表示该元素在该子集元素中
		vector<int> flags;
		//初始化
		for (int m = 0; m < nums.size(); m++)
			flags.push_back(0);
		
		intToBinary(i, flags);

		vector<int> tmp;
		for (int j = 0; j < flags.size(); j++)
		{
			if (flags[j] == 1)
			{
				tmp.push_back(nums[j]);
			}
		}

		sort(tmp.begin(), tmp.end(), sortByNum);
		//针对有可能有重复元素的集合,加入到result集之前首先判断是否已经有与待加入元素相同的元素
		bool exists = false;
		for (size_t m = 0; m < result.size(); m++)
		{
			if (tmp == result[m])
				exists = true;
		}
		if (exists == false)
			result.push_back(tmp);
	}
	return result;
}

int main()
{
	vector<int> test;
	test.push_back(1);
	test.push_back(2);
	test.push_back(2);
	vector<vector<int> > result = subsets(test);
	cout << result.size() << endl;
	for (int i = 0; i < result.size(); i++)
	{
		for (int j = 0; j < result[i].size(); j++)
		{
			cout << result[i][j] << " # ";
		}
		cout << endl;
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/lhanchao/article/details/54629065