求组合数的两种方法
- 杨辉三角的性质,第i行就是第j个元素的就是
C(i,j)
。 - 快速幂求解,有个限制就是求的组合数一般很大,也就是对结果需要取模才能用
咱们直接上两种算法的耗时
杨辉三角 | 快速幂 | |
---|---|---|
C (500, 400) | 2ms | 1ms |
C (1000, 400) | 7ms | 1ms |
C (2000, 400) | 18ms | 2ms |
可以看出快速幂完胜,尽量的都去使用快速幂算法。其实也可以将mod设的大一些,只要保证结果不大于mod,那么也是可以使用快速幂的。但是也要保证阶乘也不大于mod,因为阶乘也会取余mod。
杨辉三角求法
直接打表就可以,下面的这种打表是比较好的一种算法。空间复杂度O(n)。时间复杂度也优于一般写法,对于竞赛的同学建议模板背下来。
long mod = 1000000007;
long[] y=new long[1010]; //一般数据规模不超过1000,因为超过一千的就不用杨辉三角算了,超过一千的一般都要取模,那么就要用快速幂了
y[0]=1; //一定要初始化
for(int i=1;i<=n;i++) //n是你要求的组合数C(i,j)最大的i
for(int j=i;j>=1;j--)
y[j]=(y[j]+y[j-1])%mod;
快速幂
快速幂不理解的,可以去看这个快速幂+乘法逆元解决组合数
public class Main
{
static int mod = 1000000007;
static long[] daoshu;
static long[] jiechengs;
public static void main(String[] args) throws IOException
{
jiechengs = new long[2010]; //存放阶乘
daoshu = new long[2010]; //存放阶乘的倒数,注意通过取模他不是小数,而是一个整数
jiechengs[1]=1;
for(int i=2;i<=2000;i++)
{
jiechengs[i]=(jiechengs[i-1]*i)%mod; //前缀和思想
daoshu[i]=pow(jiechengs[i],mod-2);
}
}
static long C(int n,int m)
{
if(m==0||m==n)
return 1;
else
return jiechengs[n]*daoshu[m]%mod*daoshu[n-m]%mod;
}
//快速幂模板,还不熟悉的快去背下来这个板子
static long pow(long a,long n)
{
long ans=1;
while(n!=0)
{
if((n&1)==1)
ans=(ans*a)%mod;
a=(a*a)%mod;
n>>=1;
}
return ans;
}
}