前言
写这个博客是因为在刷题的时候有时会遇到利用排列组合就可以很容易解决的事情,但是由于不知道排列组合算法就不得不用其他方法解题(如dfs),最后就造成了超时;排列组合应对不要求列出每种情况,只要求求出有多少情况。
C(n,m)
理解
从n个字符中选取m个字符,获得所有的组合
公式一
公式二
公式二可以这么理解,从n个物品中取m个有2种情况:(1)不取第n个物品,于是从前n-1个中取m个; (2)取第n个物品,于是从前n-1个中取m-1; 所以答案是这两种情况的和
两个性质:
1.C(n,m)=C(n,n-m)
2.C(n,m)=C(n-1,m)+C(n-1,m-1);(编程时可用此递推)
代码
速度惊人
排列组合数C(m,n)的O(n)算法
public class CAndA {
// C(m,n)
private long c(long m, long n) {
//temp 为答案
long temp = 1;
//保证n>=m-n
if (n < m - n)
return c(m, m - n);
for (int i = 0; i < m - n; ++i) {
temp *= n + i + 1;
temp /= i + 1;
}
return temp;
}
public static void main(String[] args) {
CAndA cAndA = new CAndA();
long l = System.currentTimeMillis();
System.out.println(cAndA.c(100, 22));
System.out.println(System.currentTimeMillis()-l);
}
}
A(n,m)
理解
由公式A(n,m)=C(n,m)*A(m,m)可以将排列问题转换为组合问题和全排列问题,先得到C(n,m)的所有集合,然后对集合中的每一个字符串进行全排列,就得到了排列问题的解;
公式
代码
// A(m,n)
private long a(long m, long n) {
long res = 1;
for (long i = m; i > m - n; i--) {
res *= i;
}
return res;
}