如何减少这段代码以避免TLE

问题描述

该程序将查找数字阶乘中的位数

#include <stdio.h>
#include <math.h>
int main()
{
int n = 0,i,count = 0,dig ;
double sum = 0,fact;
scanf("%d",&n );
for(i=1;i<=n;i++)
{
 sum = sum + log(i);
}
fact = (exp(sum));
while(fact!=0)
{
 dig = ((int)fact%10);
 count++;
 fact = floor(fact/10);
}
printf("%d\n",count);
return 0; 
}

请随意发表评论,以改进此代码,因为我在编码方面还没有广泛的经验。

解决方法

您的代码花了这么长时间的原因是,一旦n达到约180,fact的值就会变得太大而无法容纳在双精度浮点变量中。执行此行时:

    fact = (exp(sum));

您基本上是将fact设置为无穷大。结果,以下while()循环永远不会终止。

在代码中计算对数也没有多大意义。只会减慢速度。只需在double变量中计算阶乘,并在变量太大时将其重置即可。像这样:

int factorial_digit_count(int n) {
    int i,nd=1;
    double f = 1.0;
    for (i=2; i<=n; i++) {
        f *= i;
        if (f > 1.0E+100) {
            f /= 1.0E+100;
            nd += 100;
        }
    }
    while (f > 1.0E+10) {
        f /= 1.0E+10;
        nd += 10;
    }
    while (f >= 10.0) {
        f /= 10.0;
        nd++;
    }
    return nd;
}
,

假设您不想使用任何数学计算,但想通过自己的方式“蛮力”操作,这将缩短我的运行时间(并主要清理代码)。

#include <stdio.h>
#include <math.h>
int main()
{
    int n,fact = 1;
    scanf("%d",&n );
    for (int i = 1; i < n; i++)
        fact *= i;
    
    int sum = 0;
    while (fact != 0)
    {
        fact /= 10;
        sum++
    }

    printf("%d\n",count);
    return 0; 
}

希望这能回答您的问题,祝您好运!

,

数字的基数b与该数字的基数b之间存在简单的关系:

len(repr(x,b)) = 1 + floor(log(x,b))

尤其是在以10为底的x中,数字的位数为1 + floor(log10(x))。 (要了解为什么是这种情况,请查看该公式的幂为10的结果。)

现在,a×b的对数是ab的对数之和。因此n!的对数就是1到n的整数的对数之和。如果我们以10为底进行计算,则可以轻松提取n!的十进制扩展长度。

换句话说,如果将每个值的log10而不是log求和,则可以摆脱:

fact = (exp(sum));

while(fact!=0)
{
 dig = ((int)fact%10);
 count++;
 fact = floor(fact/10);
}

并仅输出1 + floor(sum)

理论上,这可能会产生舍入误差。但是,您需要做很多对数运算才能使误差项传播到足以在计算中产生误差的程度。 (并不是说它不可能发生。但是如果发生,n确实是一个很大的数字。)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...