LeetCode.172- 阶乘后的零
Posted ZSYL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode.172- 阶乘后的零相关的知识,希望对你有一定的参考价值。
题目描述:
给定一个整数 n,返回 n! 结果尾数中零的数量。
1.计算阶乘
这种方法速度太慢了,但却是一个好的起点。虽然不会在面试中实现它,但是你可以简单的描述它是个解决问题的办法之一。
解决这个问题的最简单的办法就是计算 n!,然后计算它的末尾数 0 个数。阶乘是通过将所有在 1 和 n 之间的数字相乘计算的。例如:10!=10⋅9⋅8⋅7⋅6⋅5⋅4⋅3⋅2⋅1=3,628,800。因此,可以使用以下算法迭代计算阶乘。
代码展示:
Python
def trailingZeroes(self, n: int) -> int:
# Calculate n!
n_factorial = 1
for i in range(2, n + 1):
n_factorial *= i
# Count how many 0's are on the end.
zero_count = 0
while n_factorial % 10 == 0:
zero_count += 1
n_factorial //= 10
return zero_count
在 Java 中,我们需要使用 BigInteger,防止在计算阶乘的过程中溢出。
import java.math.BigInteger;
public int trailingZeroes(int n) {
// Calculate n!
BigInteger nFactorial = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
nFactorial = nFactorial.multiply(BigInteger.valueOf(i));
}
// Count how many 0's are on the end.
int zeroCount = 0;
while (nFactorial.mod(BigInteger.TEN).equals(BigInteger.ZERO)) {
nFactorial = nFactorial.divide(BigInteger.TEN);
zeroCount++;
}
return zeroCount;
}
2.计算因子 5
这种方法也太慢了,但是在解决问题的过程中,它很可能是提出对数方法的一个步骤。
与方法 1 中那样计算阶乘不同,我们可以认识到阶乘末尾的每个 0 表示乘以 10。
那么,我们在计算 n! 时乘以 10 的次数是多少?两个数字 aa 和 bb 相乘。例如,要执行 42⋅75=3150,可以重写如下:542⋅75=2⋅3⋅7⋅3⋅5⋅5
现在,为了确定最后有多少个零,我们应该看有多少对 22 和 55 的因子。在上面的例子中,我们有一对 22 和 55 的因子。
例如,如果 n=16,我们需要查看 1到 16 之间所有数字的因子。我们只对 2 和 5 有兴趣。包含 5因子的数字是 5,10,15,包含因子 22 的数字是 2、4、6、8、10、12、14、16。因为只三个完整的对,因此 16! 后有三个零。
class Solution:
def trailingZeroes(self, n: int) -> int:
five = 0
two = 2
for i in range(5, n+1):
cur = i
while cur % 5 == 0:
five += 1
cur //= 5
for i in range(2, n+1):
cur = i
while cur % 2 == 0:
two += 1
cur //= 2
return min(two, five)
这样我们就得到了正确答案,但是我们仍然可以做一些改进。
首先,我们可以注意到因子 2 数总是比因子 5 大。为什么?因为每四个数字算作额外的因子 2,但是只有每 25 个数字算作额外的因子 5。下图我们可以清晰的看见:
优化1
class Solution:
def trailingZeroes(self, n: int) -> int:
five = 0
for i in range(5, n+1):
cur = i
while cur % 5 == 0:
five += 1
cur //= 5
return five
优化2
我们可以做最后一个优化。在上面的算法中,我们分析了从 1 到 n 的每个数字。但是只有 5, 10, 15, 20, 25, 30, … 等等 至少有一个因子 5。所以,偶们不必一步一步的往上迭代,可以五步的往上迭代:因此可以修改为:
def trailingZeroes(self, n: int) -> int:
zero_count = 0
for i in range(5, n + 1, 5):
current = i
while current % 5 == 0:
zero_count += 1
current //= 5
return zero_count
优化3
在方法 2 中,我们找到了一种计算阶乘后的零的个数的方法,而不需要实际计算阶乘。这是通过在 55 的每个倍数上循环,从 5 到 n,并计算 5 的每个倍数中有多少个因子。我们把所有这些数字加起来得到最终结果。
然而,无论是实际上还是对问题的要求来说,方法 2 仍然太慢。为了得出一个足够快的算法,我们需要做进一步改进,这个改进能使我们在对数时间内计算出我们的答案。
def trailingZeroes(self, n: int) -> int:
zero_count = 0
while n > 0:
n //= 5
zero_count += n
return zero_count
摘自官方题解 Link
以上是关于LeetCode.172- 阶乘后的零的主要内容,如果未能解决你的问题,请参考以下文章