全排列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;
细节的朋友可以发现,这里跟上边用数组递归实现所使用的方式很相似,但仔细观察,他们还是有一定区别的。
希望这篇文章可以帮助到你对排除重复项的理解。