求全排列

Tags: 算法

1. 描述

给定一个数组a, 下标从0开始,a中的元素不重复, 求a中元素的全排列。

2. 解法

解法一:

该算法基于公式: Ann=C1n.An1n1 ,即求n个元素的全排列时可以先从n个元素集合中选出1个放在第一个位置,再对其余n - 1个元素做全排列。

#include<iostream>

using namespace std;

void doPerm(int a[], int start, int n) {
    if (start == n) {
        for (int i = 0; i < n; ++i)
            cout<<a[i]<<" ";
        cout<<endl;
    } else {
        for (int j = start; j < n; ++j) {
            swap(a[start], a[j]);
            doPerm(a, start + 1, n);
            swap(a[start], a[j]);
        }
    }
}

inline void perm(int a[], int n) {
    doPerm1(a, 0, n);
}

n等于3时,算法的求解过程可用下图表示,其中同一父节点下的一层代表一轮for循环(代码第11~15行)的执行。
perm1

不考虑输出,其时间复杂度主要在于perm的调用次数或第11行for循环的执行次数,即图中所有结点的次数为 1 + n + n * (n - 1) + … + n * (n - 1) * (n - 2) * … * 1 + n * (n - 1) * (n - 2) * … * 1, 即复杂度为O(n!)。

解法二:

穷举待输出集合b的每一个位置i,该位置未填元素(b[i]等于0),向一个集合中补给一个元素,此例子为先选a集合中下标大的元素,当集合b需要的元素个数为0时,输出该集合。

#include<cstring>
#include<iostream>

using namespace std;

void doPerm(int a[], int n, int cur, int b[]) {
    if (cur == 0) {
        for (int i = 0; i < n; ++i)
            cout<<b[i]<<" ";
        cout<<endl;
    } else {
        for (int j = 0; j < n; ++j) {
            if (b[j] == 0) {
                b[j] = a[cur - 1];
                doPerm(a, n, cur - 1, b);
                b[j] = 0;
            }
        }
    }
}

inline void perm(int a[], int n) {
    int* b = new int[n];
    memset(b, 0, n * sizeof(int));
    doPerm(a, n, n, b);
}

求解过程如下图所示, 由于每次向b中添加一个元素都会穷举一次,所以忽略输出的话,算法执行消耗主要在第12行for循环的执行次数上,n等于3时,算法的求解过程可用下图表示,其中同一父节点下的一层代表一轮for循环(代码第11~15行)的执行。

perm2

不考虑输出,其时间复杂度主要在于perm的调用次数或第11行for循环的执行次数,即为 1 * n + n + n * (n - 1) * n + … + n * (n - 1) * (n - 2) * … * 1 * n, 其执行次数显然多余解法一的执行次数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值