发现一直以来我写全排列的方法似乎有点山寨,2333
正规点的应该是,对于序列a[i..m],第i个地方的的值可以是a[i..m]中的任意一个,于是枚举k = i..m,
然后交换a[i], a[k],然后递归下去
void perm(int a[], int l, int r) {
if (l == r) {
for (int i = 0; i < r; i++) {
printf("%d ", a[i]);
}
printf("\n");
return ;
}
for (int i = l; i < r; i++) {
swap(a[l], a[i]);
perm(a, l + 1, r);
swap(a[l], a[i]);
}
}
简单的说i位置的元素就是剩下的元素里面选一个嘛,没啥问题。
然后呢,如果有重复元素咋办呢?按照我以前的山寨写法就要去重了,按内存开销可大了。
其实很简单,对于a[i]我们在剩下的里面选,重复的只选一次不就行了!所以呢,每次选的时候我们判断一下当前选的a[k],在a[i..k-1]里面是否出现过,如果出现过,说明a[i]这个位置我们已经选过a[k]这个值了,不用再重复选择了。
bool check(int a[], int l, int r) {
for (int i = l; i < r; i++) {
if (a[i] == a[r]) {
return false;
}
}
return true;
}
void perm(int a[], int l, int r) {
if (l == r) {
for (int i = 0; i < r; i++) {
printf("%d ", a[i]);
}
printf("\n");
return ;
}
for (int i = l; i < r; i++) {
if (!check(a, l, i)) {
continue;
}
swap(a[l], a[i]);
perm(a, l + 1, r);
swap(a[l], a[i]);
}
}