您的位置:首页 > 其它

阶乘相关问题

2015-07-10 21:04 363 查看
定义:
一个正整数的阶乘(英语:factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1。自然数n的阶乘写作n!。
亦即n!=1×2×3×...×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。

问题1、给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N = 10 , N! = 3628800,N!的末尾有两个0。

解析:加入完整得计算N!的阶乘,很可能发生溢出。我们可以从另外的角度出发,“哪些数相乘能的到10”。
N! = K * 10的M次方,K不能被10整除,那么N!末尾就有M个0.对N!进行质因数分解,N!=2的x次方 × 3的Y次方 × 5的Z次方 ×…… ,由于10=2×5,所以M只跟X和Z有关,每一对2和5相乘可以得到一个10,于是M = min(X,Z)。不难看出X大于等于Z,因为能被2整除的书出现的频率比被5整除的数高得多,所以吧公式化简为M = Z(能整除的5的个数);

方法1:
最直接的方法,计算i(1,2,3,……,N)的因式分解中5的指数,然后求和。

/**
* 计算N的阶乘结果末尾0的位数
* @param N 求阶乘的数
* @return N的阶乘结果末尾0的位数
*/
public static int getLowZeroNum(int N)
{
int ret = 0;
int j ;
for(int i = 1 ; i <=N ; i++)
{
j = i;
while(j % 5 == 0)
{
ret ++;
j = j / 5;
}
}
return ret;
}


方法2:公式法
公式:Z = 【N/5】 + 【N/5的平方】 + 【N/5的立方】+……, (不用担心这回事一个无穷的运算,因为总存在一个K,使得 5的K次方 > N,【N/5的K次方】 = 0。
公式中,【N/5】表示不大于N的数中5的倍数贡献一个5,【N/5的平方】表示不大于N的数中,5的平凡的倍数在贡献一个5…… 代码如下:

/**
* 计算N的阶乘结果末尾0的位数
* @param N 求阶乘的数
* @return N的阶乘结果末尾0的位数
*/
public static int getLowZeroNum2(int N)
{
int ret = 0;
while(0 != N)
{
ret += N/5;
N /= 5;
}
return ret;
}


问题2、求N!的二进制表示中最低位1的位置
把一个2进制数除以2,判断最后一个二进制位是否为0;若为0,则将此二进制数右移一位,即为商值;反之,若为1,则说明这个二进制数是奇数,无法被2整除。所以这个问题实际上等同于求N!含有质因数2的个数。即答案等于N!含有质因数2的个数加1

解法1:
N!中含有质因数2的个数,等于【N/2】+【N/4】+【N/8】+【N/16】+ ……,
具体算法如下:

/**
* N的阶乘最低位1的位置
* @param N 求阶乘的数
* @return N的阶乘最低位1的位置
*/
public static int getThePosition(int N)
{
int ret = 0;
while(0 != N)
{
N = N >> 1; //右移一位,相当于十进制除以2

ret += N; //不大于当前N的2的倍数的个数
}
return ret;
}


测试:

public static void main(String[] args)
{
//测试计算N的阶乘结果末尾0的位数
int N = 5;
System.out.println(N + "的阶乘结果末尾0的位数:" + Factorial.getLowZeroNum(N));
System.out.println(N + "的阶乘结果末尾0的位数:" + Factorial.getLowZeroNum2(N));

//测试N的阶乘最低位1的位置
System.out.println(N + "N的阶乘最低位1的位置:" + Factorial.getThePosition(N));
}


结果:
5的阶乘结果末尾0的位数:1
5的阶乘结果末尾0的位数:1
5N的阶乘最低位1的位置:3

小结:
任意一个长度为m的二进制数N可以表示为 N = b[1] + b[2]*2 + b[3]*4 + …… + b[m]*2的m-1次方 ,其中b[i]表示此二进制数第i位上的数字(1或0)。所以,若最低位b[1]为1,则说明N为奇数;反之为偶数,将其除以2,即等于将整个二进制数向低位移一位。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: