题解 | #阶乘末尾非零数字#

阶乘末尾非零数字

https://www.nowcoder.com/practice/248c8fbee56e491aa147b67b9c082da0

题目链接

HIGH3 阶乘末尾非零数字

题目描述

给定一个正整数 n,请求出 n! (n的阶乘) 的十进制表示中,从右往左数第一个非零的数字。

解题思路

这个问题的核心挑战在于 n! 的值会非常快地增长,对于稍大的 n(例如 n=20),其阶乘结果就会超出标准64位整型(long long)的存储范围。因此,直接计算出 n! 的完整值再提取末位数字是不可行的。

我们需要一种在计算过程中就能控制数值大小的方法。思路如下:

  1. 迭代计算:我们可以模拟阶乘的计算过程,从 1 乘到 n。维护一个变量 res,用于存储我们关心的“末尾部分”的乘积。

  2. 移除尾随零:阶乘结果中的尾随零是由因子 2 和 5 相乘(2 * 5 = 10)产生的。我们只关心第一个非零数字,所以每当乘积 res 的末尾出现 0,就应该立即移除它。这可以通过一个循环实现:只要 res % 10 == 0,就执行 res /= 10

  3. 防止溢出:即使移除了尾随的零,res 的值在乘以 i 时仍然可能增长得非常快,最终导致溢出。为了解决这个问题,我们可以在每次移除尾零后,对 res 进行取模操作,只保留其末尾的几位数字。例如 res %= 1000000000

    • 为什么这是可行的?因为我们最终只关心结果的个位数字 (res % 10)。保留末尾的几位(如9位)作为“缓冲区”,足以确保在下一次乘以 ii 不会太大)并移除尾零后,得到的个位数字是正确的。这个缓冲区保证了我们不会因为过早地取模而丢失影响最终结果个位数的关键信息。
  4. 特殊情况:根据数学定义,0! = 1,所以当输入为 0 时,应输出 1。

综上所述,我们的算法是:

  • 初始化 res = 1
  • i = 1 循环到 n
  • 在循环中,res *= i
  • 移除 res 的所有尾随零。
  • res 取一个较大的模(如 100000)以防止溢出。
  • 循环结束后,res % 10 就是最终答案。

代码

#include <iostream>

using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    long long n;
    cin >> n;

    if (n == 0) {
        cout << 1 << endl;
        return 0;
    }

    long long res = 1;
    for (long long i = 1; i <= n; ++i) {
        res *= i;
        while (res % 10 == 0) {
            res /= 10;
        }
        res %= 1000000000; // 保留足够的末位以防止溢出和保证精度
    }

    cout << res % 10 << endl;

    return 0;
}
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();

        if (n == 0) {
            System.out.println(1);
            return;
        }

        long res = 1;
        for (long i = 1; i <= n; i++) {
            res *= i;
            while (res % 10 == 0) {
                res /= 10;
            }
            res %= 1000000000; // 保留缓冲区
        }

        System.out.println(res % 10);
    }
}
n = int(input())

if n == 0:
    print(1)
else:
    res = 1
    for i in range(1, n + 1):
        res *= i
        while res % 10 == 0:
            res //= 10
        # Python可以处理大整数,但我们仍然可以取模
        # 以保持数字较小,从而可能加快计算速度。
        res %= 1000000000
    
    print(res % 10)

算法及复杂度

  • 算法:模拟、数学
  • 时间复杂度:。我们有一个主循环,从 1 迭代到 n。在循环内部,while 循环用于移除尾随零,其执行次数取决于 resi 中包含的因子 5 和 2 的数量,这个次数相对较小。因此,时间复杂度近似为
  • 空间复杂度:。我们只需要常数级别的额外空间。
全部评论

相关推荐

06-10 21:15
门头沟学院 Java
宁阿:好多这种没🧠的公司,他们估计都不知道毕业的人不能给安排实习岗
实习吐槽大会
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务