LeetCode 90 Subsets II--In C++

本文介绍了一种高效生成包含重复元素集合的所有子集的算法。通过排序及比较相邻元素避免重复,利用递增的方式构建所有可能的子集组合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:

由于这道题增加了冗余的属性,所以如果用Subset 1中的暴力递归进行求解的话,会浪费很多时间在扫描判断是否有重复值上。因此,类似于全排列的那个题,想到了在之前的基础上添加一个元素即可形成全新的子集的思路。

用一个vector<vector<vector<int>>> newadd变量来记录:每增加一个元素,就增加的子集

举例:

比如1,2,2这三个元素。

首先newadd中加入一个空集。当1加入之后,增加了{1}。第一个2加入后增加了{2}和{1,2}。第二个2加入后,增加了{2,2}和{1,2,3}。

规律就是,先对输入的vector<int>进行排序,得到一个上升的序列。当一个元素不等于和他相邻的前一个元素时,遍历之前所有的结果集,加上这个元素,作为增加这个元素就增加的子集。如果这个元素和他之前的那个元素重复,则遍历他之前的那个元素对应的结果集,加上这个元素,作为增加这个元素就增加的子集。

在上例中,1之前没有重复元素,遍历之前所有的结果集,只有一个空集,则新增{1}。第一个2需要遍历空集和{1},第2个2需要遍历{2}和{1,2}。

vector<vector<int>> subsetsWithDup(vector<int>& nums) {
	vector<vector<vector<int>>> newadd;
	vector<vector<int>> zero;//0个元素,相当于新增空集
	newadd.push_back(zero);

	int m = nums.size();
	if (m==0){
		return zero;
	}
	vector<vector<int>> result;
	//要排序
	sort(nums.begin(), nums.end());


	for (int i = 1; i <= m;i++){
		if (i==1 || nums[i-1]!=nums[i-2]){
			//如果是nums的第一个元素或这个元素与其前一个不相同
			//需要全部遍历之前的newadd元素,并新增
			vector<vector<int>> mynewadd;
			for (int j = 0; j < i;j++){
				int len = newadd[j].size();//第j个元素新增的子集数
				if (len==0){
					vector<int> everyelement;
					everyelement.push_back(nums[i-1]);
					mynewadd.push_back(everyelement);
					continue;
				}
				for (int k = 0; k < len;k++){//依次取出第j个元素的新增子集
					vector<int> everyelement = newadd[j][k];
					everyelement.push_back(nums[i-1]);
					mynewadd.push_back(everyelement);
				}
				
			}
			newadd.push_back(mynewadd);
		}
		else if(nums[i-1]==nums[i-2]){
			//如果和前一个元素重复
			//只在前一个元素新增集上新增
			vector<vector<int>> mynewadd;
			int len = newadd[i - 1].size();
			for (int k = 0; k < len;k++){
				vector<int> everyelement = newadd[i-1][k];
				everyelement.push_back(nums[i-1]);
				mynewadd.push_back(everyelement);
			}
			newadd.push_back(mynewadd);
		}
		
	}
	//再循环拿出每个新增,整个进一个结果集中返回
	for (int i = 0; i <= m;i++){
		for (int j = 0; j < newadd[i].size();j++){

			/*for (vector<int>::iterator it = newadd[i][j].begin();
				it != newadd[i][j].end();it++){
				cout << *it << " ";
			}
			cout << endl;*/
			result.push_back(newadd[i][j]);
		}
	}
	vector<int> tempzero;
	result.push_back(tempzero);
	return result;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值