阶乘的概念很多人都很熟悉,但在计算机领域,计算一个整数的阶乘无疑会让这个数疯狂增长。如果溢出了,该如何处理这些数据带来的操作?今天看到一个关于阶乘的面试问题。感觉踩坑比较容易写下来分享~ ~ ~
1.给定一个整数n,那么n的阶乘就是n!末尾有多少个零?例:n=10,n!=3 628 800,N!的末尾有两个零。
如果看到这个问题,应该把n放在第一位!计算末尾的零的数量。恭喜踩坑。我从这个开始。
代码实现如下:
int GetZeroCount1(int N)
{
//计算零个数前的阶乘,容易溢出。
if (N==0 || N==1) //0!=1 1!=1,必须没有0,所以返回0
返回0;
int count=0;
int Mul=1;
for(int I=2;I=N;(一)
{
mul *=I;
}
while (Mul)
{
if (Mul==0)
{
计数;
}
mul/=10;
}
返回计数;
}
你是不是觉得这个代码特别低?如果给你一个特别大的n,先放n!算了算,电脑能不能存储还是个问题。如何求末尾零的个数?
[解决方案1]
如果我们从哪些数字可以相乘得到10的角度来思考这个问题,就会变得简单。
首先,我们可以放n!变换n!=K*(10*M),其中K不能被10整除,也就是说n!结尾有m个零,所以,嘿,n!只跟m有关系;
然后我们放n!执行以下质因数分解:n!=(2 x) * (3 y) * (5 z).因为10=2*5。所以可以翻译成M只与x,z有关M=Min{x,z},因为可被2整除的数的频率远高于可被5整除的数(x的频率大于z的频率);
最后,这个问题可以转化为求z的值,然后我们就可以求n了!结尾的零的数量。
代码实现如下:
int GetZeroCount2(int N)
{
//转换为5的倍数。
//N!=K*(10*M),K不能被10整除。这个问题转化为求m的大小。
//分解n!=(2*X)*(3*Y)*(5*Z),因为2*5=10,所以可以转换成X和Z的较小值。
//M=Min{X,Z},因为2的倍数在一个数据中多次出现,最终转化为5的倍数。
int count=0;
if (N==0 || N==1)
返回0;
for(int I=1;I=N;(一)
{
int j=I;
while (j % 5==0)
{
计数;
j/=5;
}
}
返回计数;
}
[解决方案2]
首先,给出一个公式z=[n/5][n/5 ^ 2][n/5 ^ 3].第二种解决方案是基于对第一种解决方案的理解。不要担心这个解会是一个无止境的循环,这是由上面提到的n决定的!=K*(10*M)公式表明,总有一个k不能被10等分,这使得5^K0,所以[n/5k]=0;
在公式中,【N/5】表示不大于N的数中的5的倍数贡献一个5,而【N/5 ^ 2】表示不大于N的数中的5 ^ 2的倍数贡献另一个5。
代码实现如下:
int GetZeroCount3(整数N)
{
int count=0;
if (N==0 || N==1)
返回0;
而(N)
{
计数=N/5;
n/=5;
}
返回计数;
}
[解决方案3]
先存储一些数据,然后统计0的出现次数。如果大于MAX,只能保存最后五位数字。
const int MAX=100000
int GetZeroCount4(int N)
{
//先存储一些数据。
int sum=1;
int count=0;
if (N==0 || N==1)
返回0;
for(int I=N;I=1;i -)
{
sum *=I;
While (sum% 10==0) //计算0的出现次数。
{
sum/=10;
计数;
}
如果(总和=最大值)//如果总和太大,将只存储最后五位数字。
{
总和%=MAX
}
}
While (sum% 10==0) //计算0的出现次数。
{
sum/=10;
计数;
}
返回计数;
}
2.求n!的二进制表示形式中最低位1的位置。例如N=5,N!=5!=120,120在二进制中表示为0111,000,其二进制中最低位1的位置是第四位。
当然,如果你先问n这个问题!值,会出现与第一个问题类似的问题。如果溢出了怎么办?嗯,只能改造了~ ~ ~
我们知道的是,一个数除以2相当于向右移动一个位置。有了上面的概念,第二个问题就可以转化了!可以相当于找n!中质因数2的个数。
代码实现如下:
整数1(整数N)
{
int pos=1;//从最后一位开始
而(N)
{
n=1;
pos=N;
}
退货单;
}
当然关于阶乘的话题有很多,今天就来分享一下吧!