提起全排列,第一印象是不是大学概率中的排列和组合呢,回头翻了翻书(怪自己太笨,记不住),才发现全排列是排列的一种。那就先延伸一下排列
和组合
呗。
排列
一般地说,从n个不同元素中,任取m(m≤n)个元素,按照一定的顺序排成一列,这就叫做从n个元素中取出m个元素的一个排列。
在排列数公式中,当m=n时,有:
这表明,n个不同元素全部取出来排列的排列数等于自然数1到n的连乘积。n个不同元素,全部取出的一个排列叫做n个不同元素的一个全排列。
自然数1到n的连乘积叫做n的阶乘,用n!表示,所以n个不同元素的全排列公式则为:
例如:写出一个数组{a,b,c}的全排列。
对于初学者可以先画下图来算出:
共6个排列,这个数值6是可以根据乘法原理算出来的。第一次有3种选择,第二次有2种选择,第三次就有1种选择。据此共有N=3 X 2 X 1=6种。
先看两道题,旷视最近笔试考了这么一道题:
对于这道题你有思路吗?可以这样考虑:
a) 七人的全排列有A(7,7)=5040种排法,由于A,B是对等的,也就是说A在B的左边和B在A的左边的
站法数量是相同的,所以有A(7,7)/2=2520种;
b)把AB当成一个整体,求全排列,就是6! = 720
算法实现
public static void perm(int A[], int p, int q){
if(p == q){
// 输出所有结果
printAll(A, q+1);
}else{
int i;
for(i=p; i<=q; i++){
// 交换
swap(A, p, i);
perm(A, p+1, q);
swap(A, p, i);
}
}
}
}
算法讲解
这里的实现使用了递归,递归需要满足是三个条件:
- 一个问题的解可以分解为几个子问题的解;
- 这个问题与分解之后的子问题,除了数据规模不同,求解思路完全一样;
- 存在递归终止条件
我们依次对标,上面对3个字母求全排列对递归的使用不太明显,我们来举4个数字的例子
通过上述的输出结果,可以通过debug断点走一遍,你应该可以理解。其中,第一个swap()是把每个元素都和第一个元素进行交换,第二个swap()方法是将上一次的交换归为原位置,避免重复。