质数分解——解决一个有关阶乘问题

题目:给定一个整数N,请问N!这个数末尾有多少个0?

解决方案1:计算N!,并搜索其末尾,判断0的个数。N!可能过大,数会溢出,如果用该办法,需自己完成一个大数乘法的类,才会好用!

解决方案2:对N!进行质因数分解,可知N!=pow(2,x)*pow(3,y)*pow(5,z)...,能让末尾有零的必然是2*5。可以想见,2的个数远多于5的个数,即 x>z ,所以,末尾应该有z个0。

解决方案2的代码1:

public static int calZero(int a){
		int ret=0;
		for(int i=1;i<=a;++i){
			if(i%5==0){
				int j=i;
				while(j%5==0){
					ret++;
					j=j/5;
				}
			}
		}
		return ret;
	}

对代码1的分析:

事实上,while语句中就具备了if语句判断的功能,多写一个if语句是毫无意义。所以应修改为:

代码2:

	public static int calZero(int a){
		int ret=0;
		for(int i=1;i<=a;++i){
			int j=i;
			while(j%5==0){
				ret++;
				j=j/5;
			}
		}
		return ret;
	}

对于这个问题,网上有更简短的代码:

代码3:

	public static int calZero(int a){
		int ret=0;
		while(a>0){
			ret+=a/5;
			a/=5;
		}
		return ret;
	}

对于代码3的分析:

从思想的角度来看,代码2和代码3都是同样的思考方式,即计算N!中质因数的个数。在代码3中,计算方法是 Z=[N/5]+[N/25]+[N/125]+... ,可理解为,[N/5]不大于N的数中,5的倍数贡献一个5,[N/25]表示不大于N的数中25的倍数再次贡献一个5,以此类推。如N=25时,5的倍数有5,10,15,20,25,其中5、10、15、20均贡献1个5,25贡献2个5,因为25=5*5!


============================================================


题目:给定整数N,求N!的二进制标识中最低位1的位置

解决方法1:依旧是求出N! 然后转换二进制,并最终得结果。缺点:复杂,需考虑数的溢出问题。

解决方法2:判断一个二进制数的最低位1的位置,可如下判断:检查当前是否为1,不是则将该二进制数右移一位。循环直至当前末位为1。所以,欲求N! 二进制表示中最低位1的位置,即可将N!的二进制表示右移,直至末位为1。由于右移在算术中是除2的意思,所以该问题的实质就是求N!中含质因数2的个数!最后的答案为N!中含质因数2的个数加1。

代码:

	public static int loc(int N){
		int ret=0;
		while(N!=0){
			N>>=1;
			ret+=N;
		}
		return ret+1;
	}

代码分析:

代码思想是计算N!中质因数为2的个数,即为 [N/2]+[N/4]+[N/8]+[N/16]+... 。




总结:

质因数的分解是解决有关数字的算法问题的一个思考方向,其中的思想还蛮巧妙。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值