问题陈述
- 给定一个整数N,N的阶乘N!中末尾有多少个0?
- N! 的二进制表示中最低位1的位置?
问题1的O(N2)解法
如果N! = K x 10M, K是不能被10整除的数。
M 表示 N!的末尾有M个0。
可以看到,N!的末尾有多少个0,和N!的分解式中10的个数有关。
对 N! 进行质因数分解 N! = (2X) x (3Y) x (5Z)......。
因此M只和质因数分解式中2的个数和5的个数有关。即 M = min(X, Z)
由于从1-N中,能被2整除的数出现的频率 肯定大于 能被5整除的数出现的频率。
因此,M = Z;
因此得到我们的时间复杂度O(N2)朴素的解法:
public static int numOfZeroINFactorial_1(int N){
int res=0;
for(int i=1; i<=N; ++i){
int j = i;
while(j % 5 == 0){
res++;
j /= 5;
}
}
return res;
}
问题1的O(N)解法
k是正整数, floor(N/k)表示 1,2,3,...., N中能被k整除的数的个数。
证明:
假设1,2,3,...., N中有m个数可以被k整除,则共有
1k, 2k, 3k, ..., mk(mk<=N)个数可以被k整除。显然,m=floor(N / k) 就是正解。
因此,M = floor(N/5) + floor(N / 52) + floor(N / 53) + ... 0.
该式表示,N!中含有质因数5的个数。
public static int numOfZeroINFactorial_2(int N){
int res=0;
while(N!=0){
res += (N/5);
N /= 5;
}
return res;
}
问题2的O(N)解法1
问题分析
求解N! 的二进制表示中最低位1的位置。等价于 求解N!的二进制表示中最后有多少个0. 原问题的解就是0的个数加1.
将 N! 进行质因数分解 N! = (2X) x (3Y) x (5Z)......后,质因数2的个数就是N!的二进制表示中最后的0的个数。
N!中质因数2的个数等于 floor(N/2) + floor(N / 22) floor(N / 23) + ... +0.
代码如下:
public static int solution1(int N){
int res=0;
while(N!=0){
res += (N >> 1);
N >>= 1;
}
return res+1;
}
问题2的O(N)解法2
N!中质因数2的个数等于N减去N的二进制表示中1的数目
证明:
N!中质因数2的个数等于 floor(N/2) + floor(N / 22) floor(N / 23) + ... +0.
假设N=11011则
1101 + 110 + 11 + 1
=(1000 + 100 + 1)
+(100 + 10)
+(10 + 1)
+(1)
=(1000 + 100+ 10 + 1)+(100 + 10 + 1)+ 1
= 1111 + 111 + 1
=(10000 -1)+(1000 - 1)+(10-1)+(1-1)
= 11011 - N二进制表示中1的个数
private static int numOne(int v){
int num = 0;
while(v!=0){
v &= (v-1);
num++;
}
return num;
}
res = N - numOne(N);
扩展问题1
给定整数N,判断它是否是2的方幂。
N>0 && ( (N&(N-1))==0 )