全排列、排列组合(去重区别)

全排列and排列组合

实现排除重复项的细微区别
本篇文章以 全排列方法,和排列组合来进行阐述。
这里的排列组合用了一道例题来展开**(目标值的不同组合方式)**

首先是全排列,用了两种方式来实现 :1.swap交换,2:数组递归
实质都是递归,但他们排除数据重复项还是有一定区别的。

一、全排列
1.swap交换法代码:

#include<iostream>
using namespace std;
int tmp[3];
void print()//打印数据部分
{
	for (auto v : tmp)
	{
		cout << v << '\t';
	}
	cout << endl;
}
bool check(int tmp[], int start, int end)//排除重复项。
{
	for (int i = start; i < end; i++)
	{
		if (tmp[i] == tmp[end])return false;
	}
	return true;
}
void prim(int tmp[], int start, int end)//递归实现
{
	if (start == end - 1) { print(); return; }
	for (int i = start; i < end; i++)
	{
		if (!check(tmp,start,i))continue;
		swap(tmp[i], tmp[start]);
		prim(tmp, start + 1, end);
		swap(tmp[i], tmp[start]);
	}
}
int main()
{
	for (int i = 0; i < 3; i++)
	{
		cin >> tmp[i];
	}
	prim(tmp,0, 3);
	return 0;
}

2.数组递归方式:

#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>>kk;
void dfs(vector<int>& num, vector<int>& used, vector<int>& list)
{
   if (list.size() == num.size()) { kk.push_back(list); return;}
   for (int i = 0; i < num.size(); i++)
   {
   	if (i > 0 && num[i] == num[i - 1] &&!used[i - 1])continue;
   	//上边这个if就是实现排除重复项的关键。
   	if (!used[i])
   	{
   		used[i] = 1;
   		list.push_back(num[i]);
   		dfs(num, used, list);
   		list.pop_back();
   		used[i] = 0;
   	}
   }
}
int main()
{
   vector<int>num{ 1,3,5,6 };
   vector<int>used(num.size()), list;
   dfs(num, used, list);
   for (int i = 0; i < kk.size(); i++)
   {
   	for (int j = 0; j < kk[i].size(); j++)
   	{
   		cout << kk[i][j] << " ";
   	}
   	cout << endl;
   }
   return 0;
}

我们将两份代码实现排除重复项的部分提取出来
前者 :使用了一个bool函数。

bool check(int tmp[], int start, int end)//排除重复项。
{
	for (int i = start; i < end; i++)
	{
		if (tmp[i] == tmp[end])return false;
	}
	return true;
}


if (!check(tmp,start,i))continue;

后者: 直接使用一行代码就能实现。

if (i > 0 && num[i] == num[i - 1] &&!used[i - 1])continue;

学习的过程是坎坷的,可以写一个简单的测试数据来理解其中的原理,
其中swap实现排除重复项的细节是比较丰富的,这里推荐的测试数据:1232
自己推理看看其中的过程。
才能感受到这两种实现方式的真谛!!!

二、接下来是排列组合 实现排除重复项,过程又与上边两种有一定细节区别。

牛客上可以去做一做 目标值的组合方式一系列的题帮助提示。
这里我们以其中一道展开讨论

#include <iostream>
#include <vector>
#include<algorithm>  //sort()头文件
using namespace std;
vector<int>arr{ 100,10,20,70,60,10,10,50 };
int target = 80;
vector<vector<int>>tmp;
void test(vector<int>& arr, int target, int start, vector<int>& list)
{
	if (target <= 0) { if (target == 0)tmp.push_back(list); return; }
	for (int i = start; i < arr.size(); i++)
	{
		if (i > start && arr[i] == arr[i - 1])continue;
		list.push_back(arr[i]);
		test(arr, target - arr[i], i + 1, list);
		list.pop_back();
	}
}
int main()
{
	vector<int>list;
	sort(arr.begin(), arr.end());
	test(arr, target, 0, list);
	for (int i = 0; i < tmp.size(); i++)
	{
		for (int j = 0; j < tmp[i].size(); j++)
		{
			cout << tmp[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}

将其中实现排除重复项的代码提取出来

if (i > start && arr[i] == arr[i - 1])continue;

细节的朋友可以发现,这里跟上边用数组递归实现所使用的方式很相似,但仔细观察,他们还是有一定区别的。

希望这篇文章可以帮助到你对排除重复项的理解。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值