全排列问题
1.全排列的递归实现
全排列就是从第一个数字起每个数分别与它后面的数字交换
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//递归实现
void allRange(string s, int k, int m)
{
if (k == m){
static int s_i = 1;
cout << "第" << s_i++ << "个排列是:" << s << endl;
}
else{
for (int i = k; i <= m; i++){
swap(s[i], s[k]);
allRange(s, k + 1, m);
swap(s[i], s[k]);
}
}
}
int main() {
string s = "abc";
allRange(s, 0, s.length() - 1);
return 0;
}
运行结果:
第1个排列是:abc
第2个排列是:acb
第3个排列是:bac
第4个排列是:bca
第5个排列是:cba
第6个排列是:cab
但是这没有考虑到序列中重复的情况
第1个排列是:abb
第2个排列是:abb //重复
第3个排列是:bab
第4个排列是:bba
第5个排列是:bba //重复
第6个排列是:bab //重复
2.去重的全排列的递归实现
去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool needSwap(string s, int k, int m) {
for (; k < m; k++)
if (s[k] == s[m])
return false;
return true;
}
//递归实现
void allRange(string s, int k, int m)
{
if (k == m){
static int s_i = 1;
cout << "第" << s_i++ << "个排列是:" << s << endl;
}
else{
for (int i = k; i <= m; i++){
if (!needSwap(s, k, i))
continue;
swap(s[i], s[k]);
allRange(s, k + 1, m);
swap(s[i], s[k]);
}
}
}
int main() {
string s = "abb";
allRange(s, 0, s.length() - 1);
return 0;
}
运行结果:
第1个排列是:abb
第2个排列是:bab
第3个排列是:bba
3.全排列的非递归实现
要考虑全排列的非递归实现,先来考虑如何计算字符串的下一个排列。如"1234"的下一个排列就是"1243"。只要对字符串反复求出下一个排列,全排列的也就迎刃而解了。
如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,“20”、"52"都是非递增的,“26 “即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220”,然后再将替换点后的字符串"6220"颠倒即得到"950226”。
对于像"4321"这种已经是最“大”的排列,采用STL中的处理方法,将字符串整个颠倒得到最“小”的排列"1234"并返回false。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool nextArrangement(string &s) {
int index = -1;
for (int i = s.length() - 1; i > 0; i--) {
if (s[i] > s[i - 1]) {
index = i - 1;
break;
}
}
if (index == -1)
return false;
for (int i = s.length() - 1; i > index; i--) {
if (s[i] > s[index]) {
swap(s[i], s[index]);//交换
reverse(s.begin() + index + 1, s.end());
break;
}
}
return true;
}
int main() {
string s = "abc";
int count = 1;
do {
cout << "第" << count++ << "个排列是:" << s << endl;
} while (nextArrangement(s));
return 0;
}
运行结果:
第1个排列是:abc
第2个排列是:acb
第3个排列是:bac
第4个排列是:bca
第5个排列是:cab
第6个排列是:cba