《算法笔记》读书记录DAY_14

这篇博客探讨了计算阶乘和组合数的优化算法。对于阶乘问题,提出了利用质因数p的个数来计算n!中质因子p的个数,实现了O(logn)的时间复杂度。对于组合数C(n,m)的计算,提供了三种方法:直接计算(易溢出)、递推公式(动态规划优化)和定义式变形。这些算法对于大数值的计算具有更高的效率。

CHAPTER_5  数学问题入门

5.8.1关于n!的问题

n!表示n的阶乘,即 n!=1\times 2\times 3\times...\times n 。

我们来讨论一个问题:求n!中有多少个质因子p。例如 6=1\times 2\times 3\times 4\times 5\times 6 。于是6!中有4个质因子2,因为2、4、6中各有1个2、2个2、1个2。

对于这个问题,直观的想法是计算从1~n每个数各有多少个质因子。即从2枚举到n,统计每个数中质因子p的个数。但是这种做法对n很大的情况是无法承受的,我们下面探讨更优的算法。

我们来看一个例子:10!质因子2的个数。

上例中,10!中有因子 2^{1} 的数的个数为5,有因子 2^{2} 的数的个数为2,有因子 2^{3} 的数的个数为1。因此10!质因子2的个数为5+2+1=8。

仔细思考可以将上面过程推广为一个结论:n!中有 (\frac{n}{p}+\frac{n}{p^{2}}+\frac{n}{p^{3}}+...) 个质因子p,其中除法均为向下取整。于是得到了O(logn)的算法,代码如下:

int cal(int n,int p) {
	int sum=0;
	while(n) {
		sum+=n/p;
		n/=p;
	}
	return sum;
}

5.8.2组合数的计算(1)

组合数 C_{n}^{m} 是指从n个不同元素中选择m个元素的方案,也可写成C(n,m)。其计算式为C_{n}^{m}=\frac{n!}{m!(n-m)!} 。

这里还要提及组合数的两个性质:(1)C_{n}^{m}=C_{n}^{n-m} ;(2)C_{n}^{0}=C_{n}^{n}=1 。

本节我们讨论组合数的第一个问题:如何计算 C_{n}^{m} 。下面给出3种方法。

方法1:通过计算式直接计算

 C_{n}^{m}=\frac{n!}{m!(n-m)!} ,我们先计算n!,然后令其分别除以m!和(n-m)!。显然,由于阶乘的庞大,这种方式计算组合数能接受的数据范围会很小,即使用long long类型也只能接受n<=20的数据范围。此法很容易造成溢出

方法2:通过递推公式计算

首先我们要介绍一个递推公式:C_{n}^{m}=C_{n-1}^{m}+C_{n-1}^{m-1} 。有了递推式,我们还需要确定递归边界。从直观上看,这个公式总是把n减一,而把m保持原样或者也减一,这样这个递推式最终可以把n和m变得相同,或是把m变成0。根据上面介绍的性质 C_{n}^{0}=C_{n}^{n}=1 ,我们得以确定边界。代码如下:

long long cal(long long n,long long m) {
	if(n==m||m==0)
		return 1;
	else
		return cal(n-1,m)+cal(n-1,m-1);
}

实际上,上面的算法还可以优化。 在上面的递归时,会有很多C(n,m)是重复计算过的。我们用一个数组来记录C(n,m)计算的结果,如果下一次碰到就不用再重复计算了。

long long res[500][500]={0};

long long cal(long long n,long long m) {
	if(n==m||m==0)
		return 1;
	else if(res[n][m])
		return res[n][m];
	else {
		res[n][m]=cal(n-1,m)+cal(n-1,m-1);
		return res[n][m];
	}
}

方法3:通过定义式的变形来计算 

该算法时间复杂度为O(m),代码如下:

long long cal(long long n,long long m) {
	long long sum=1;
	for(long long i=1;i<=m;i++) {
		sum=sum*(n-m+i)/i;        //一定要先乘后除,才能保证结果为整数 
	}
	return sum;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值