解这道题之前首先需要会计算下面的问题。
1、求N的阶乘末尾存在多少个0。
(1)为什么会产生0?这是因为2x5=10,只要是2和5的公倍数相乘就会产生“0”
(2)输出1!~ 100!的值,观察发现每隔5个数就产生一个0,每隔5x5个就多加一个0,(比如25,50,75,100)每隔5x5x5个数又增加一个0(比如125,250,750)... 并且100!有24个“0”。
@Test
public void test2(){
BigInteger big = new BigInteger("1");
BigInteger big2 = new BigInteger("1");
BigInteger sum = new BigInteger("0");
// 此方法返回 -1、0 或 1,因为此 BigInteger 在数值上小于、等于或大于 val。
// 只要小于101就继续
while(big2.compareTo(new BigInteger("101")) == -1){
big = big.multiply(big2);
System.out.println(big);
sum = sum.add(big);
big2 = big2.add(new BigInteger("1"));
}
System.out.println("sum:"+ sum);
}
(3)规律:
eg:
100!有多少个“0”?
100/5 = 20 -> 100里面有20个数是5的倍数;
100/25 = 4 -> 100里面有4个数是25的倍数;
100/125 = 0 ->100里面没有125的倍数,
因此100里面有 100/5 + 100/25 = 20+4 = 24个“0”。
eg:
1000!有多少个“0”?
1000/5 = 200 -> 1000里面有200个数是5的倍数;
1000/25 = 40 -> 1000里面有40个数是25的倍数;
1000/125 = 8 ->1000里面有8个数是125的倍数;
1000/625 = 1 ->1000里面有1个数是625的倍数;
1000/3125 = 0 ->1000里面有0个数是3125的倍数;
因此100里面有 1000/5 + 1000/25 + 1000/125 + 1000/625 = 200+40+8+1 = 249个“0”。
以此类推。
注意:尽管25=5x5有两个因子5,但是在计算5的倍数的时候已经算过一遍了,所以这里只算一次就可以了。
最终求n!末尾有几个“0”的代码:
(BIgInteger是大整数,可以计算较大的n!)
public void test(){
// 法1
// int n = 2009;
// int param = 5;
// int count = 0;
// int c = 1;
// while(c != 0){
// c = n/param;
// count += c;
// param *= 5;
// }
// System.out.println(count);
// 法2
int n = 2009;
int count = 0;
for(int i = 0; i < n; i++){
n /= 5;
count += n;
}
System.out.println(count);
// 法3
BigInteger big = new BigInteger("1000");
BigInteger count = new BigInteger("0");
while( big.compareTo(new BigInteger("0")) == 1){
big = big.divide(new BigInteger("5")); //除法
count = count.add(big);
}
System.out.println(count);
}
2、现在给出数字Q,请找到最小的N,使得N!末尾恰好有Q个0。
eg:
Q = 24; 求N=?
(二分查找法)
public int cnt(int n){
int count = 0;
for(int i = 0; i < n; i++){
n /= 5;
count += n;
}
return count;
}
@Test
public void test4(){
int Q = 249;
int left = 0;
int right = Q * 5;
int middle = 0;
while(left <= right){
// 中间数
middle = (left+right)/2;
if(cnt(middle) < Q){
left += 1;
}else if(cnt(middle) > Q){
right += 1;
}else{
break;
}
}
System.out.println(middle);
}