|
| 1 | +# 题目描述(简单难度) |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +给定一个数,求出一个数的阶乘末尾有多少个 0。 |
| 6 | + |
| 7 | +# 解法一 |
| 8 | + |
| 9 | +之前小红书面试的时候碰到的一道题,没想到又是 leetcode 的原题。这种没有通用解法的题,完全依靠于对题目的分析理解了,自己当时也是在面试官的提示下慢慢出来的,要是想不到题目的点,还是比较难做的。 |
| 10 | + |
| 11 | +首先肯定不能依赖于把阶乘算出来再去判断有多少个零了,因为阶乘很容易就溢出了,所以先一步一步理一下思路吧。 |
| 12 | + |
| 13 | +首先末尾有多少个 `0` ,只需要给当前数乘以一个 `10` 就可以加一个 `0`。 |
| 14 | + |
| 15 | +再具体对于 `5!`,也就是 `5 * 4 * 3 * 2 * 1 = 120`,我们发现结果会有一个 `0`,原因就是 `2` 和 `5` 相乘构成了一个 `10`。而对于 `10` 的话,其实也只有 `2 * 5` 可以构成,所以我们只需要找有多少对 `2/5`。 |
| 16 | + |
| 17 | +我们把每个乘数再稍微分解下,看一个例子。 |
| 18 | + |
| 19 | +`11! = 11 * 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 11 * (2 * 5) * 9 * (4 * 2) * 7 * (3 * 2) * (1 * 5) * (2 * 2) * 3 * (1 * 2) * 1 ` |
| 20 | + |
| 21 | +对于含有 `2` 的因子的话是 `1 * 2, 2 * 2, 3 * 2, 4 * 2 ...` |
| 22 | + |
| 23 | +对于含有 `5` 的因子的话是 `1 * 5, 2 * 5...` |
| 24 | + |
| 25 | +含有 `2` 的因子每两个出现一次,含有 `5` 的因子每 `5` 个出现一次,所有 `2` 出现的个数远远多于 `5`,换言之找到一个 `5`,一定能找到一个 `2` 与之配对。所以我们只需要找有多少个 `5`。 |
| 26 | + |
| 27 | +直接的,我们只需要判断每个累乘的数有多少个 `5` 的因子即可。 |
| 28 | + |
| 29 | +```java |
| 30 | +public int trailingZeroes(int n) { |
| 31 | + int count = 0; |
| 32 | + for (int i = 1; i <= n; i++) { |
| 33 | + int N = i; |
| 34 | + while (N > 0) { |
| 35 | + if (N % 5 == 0) { |
| 36 | + count++; |
| 37 | + N /= 5; |
| 38 | + } else { |
| 39 | + break; |
| 40 | + } |
| 41 | + } |
| 42 | + } |
| 43 | + return count; |
| 44 | + |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | +但发生了超时,我们继续分析。 |
| 51 | + |
| 52 | +对于一个数的阶乘,就如之前分析的,`5` 的因子一定是每隔 `5` 个数出现一次,也就是下边的样子。 |
| 53 | + |
| 54 | +`n! = 1 * 2 * 3 * 4 * (1 * 5) * ... * (2 * 5) * ... * (3 * 5) *... * n` |
| 55 | + |
| 56 | +因为每隔 `5` 个数出现一个 `5`,所以计算出现了多少个 `5`,我们只需要用 `n/5` 就可以算出来。 |
| 57 | + |
| 58 | +但还没有结束,继续分析。 |
| 59 | + |
| 60 | +`... * (1 * 5) * ... * (1 * 5 * 5) * ... * (2 * 5 * 5) * ... * (3 * 5 * 5) * ... * n` |
| 61 | + |
| 62 | +每隔 `25` 个数字,出现的是两个 `5`,所以除了每隔 `5` 个数算作一个 `5`,每隔 `25` 个数,还需要多算一个 `5`。 |
| 63 | + |
| 64 | +也就是我们需要再加上 `n / 25` 个 `5`。 |
| 65 | + |
| 66 | +同理我们还会发现每隔 `5 * 5 * 5 = 125 ` 个数字,会出现 `3` 个 `5`,所以我们还需要再加上 `n / 125` 。 |
| 67 | + |
| 68 | +综上,规律就是每隔 `5` 个数,出现一个 `5`,每隔 `25` 个数,出现 `2` 个 `5`,每隔 `125` 个数,出现 `3` 个 `5`... 以此类推。 |
| 69 | + |
| 70 | +最终 `5` 的个数就是 `n / 5 + n / 25 + n / 125 ...` |
| 71 | + |
| 72 | +写程序的话,如果直接按照上边的式子计算,分母可能会造成溢出。所以算 `n / 25` 的时候,我们先把 `n` 更新,`n = n / 5`,然后再计算 `n / 5` 即可。后边的同理。 |
| 73 | + |
| 74 | +```java |
| 75 | +public int trailingZeroes(int n) { |
| 76 | + int count = 0; |
| 77 | + while (n > 0) { |
| 78 | + count += n / 5; |
| 79 | + n = n / 5; |
| 80 | + } |
| 81 | + return count; |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +# 总 |
| 86 | + |
| 87 | +更偏向于数学题,主要是对问题的归纳总结。 |
0 commit comments