FCTRL-SPOJ上的阶乘

时间:2018-07-26 07:21:06

标签: c# algorithm

有人能帮助我解决我犯的错误吗?这是一个简单的问题,可以计算数字的阶乘尾随零点

输出在Ideone上可以成功运行,但是由于某些原因抛出

  

“答案错误”

在SPOJ的编译器上。

有人可以找出我犯的错误

https://ideone.com/BTVOfu

using System;

public class Test
{
    public static void Main(string[] args)
    {
        int numberOfValues = int.Parse(Console.ReadLine());
        int[] values = new int[numberOfValues];

        for(int i=0;i<numberOfValues;i++)
        {
            values[i] = int.Parse(Console.ReadLine());
        }

        for (int i = 0; i < numberOfValues; i++)
        {
            Console.WriteLine(calculateFact(values[i]));
        }

        Console.ReadKey();
    }

    static int calculateFact(int value)
    {
        int finalValue = 0;
        for (int i = 0; value > 5; i++)
        {
            value = value / 5;
            finalValue += value;
        }

        return finalValue;
    }
}

2 个答案:

答案 0 :(得分:3)

现在是实施和运行一些测试来找出“错误答案”的时候了:

using System.Linq;
using System.Numerics;

...

// Slow, ugly but easy to understand and check routine
static int naiveCount(int value) {
  BigInteger factorial = 1;

  for (int i = 1; i <= value; ++i)
    factorial *= i;

  return factorial.ToString().Length - factorial.ToString().TrimEnd('0').Length;
}

...

var counterExamples = Enumerable
  .Range(0, 100)
  .Select(v => new {
     value = v,
     actual = calculateFact(v),
     expected = naiveCount(v), })
  .Where(item => item.expected != item.actual)
  .Select(item => $"value: {item.value,4} actual: {item.actual,3} expected: {item.expected,3}");

Console.Write(string.Join(Environment.NewLine, counterExamples));

结果:

value:    5 actual:   0 expected:   1
value:   25 actual:   5 expected:   6
value:   26 actual:   5 expected:   6
value:   27 actual:   5 expected:   6
value:   28 actual:   5 expected:   6
value:   29 actual:   5 expected:   6

拥有个计数器示例时,例如calculateFact(5)情况下调试很容易。现在可以看到问题了吗?在for循环中:

for (int i = 0; value > 5; i++)

应为(>=而不是>

for (int i = 0; value >= 5; i++)

编辑:从技术上讲,您要做的就是检查5的幂:

static int calculateFact(int value) {
  int result = 0;

  // 13 loops = floor(log(2**31)/log(5))
  for (int power5 = 5; power5 <= int.MaxValue / 5; power5 *= 5) 
    result += value / power5;

  return result;
}

答案 1 :(得分:1)

您可能会遇到内存不足错误。您不需要int[] values。您可以在读取数字后立即计算阶乘。而且您不需要Console.ReadKey();。请注意,我尚未检查calculateFact的正确性。

正如德米特里(Dmitry)所指出的那样,您的功能有误……您“一气之下”:

for (int i = 0; value >= 5; i++)

看到>=吗?但是您可以通过删除i变量来加快速度。

static int calculateFact(int value)
{
    int finalValue = 0;

    while (true)
    {
        value /= 5;

        if (value == 0)
        {
            return finalValue;
        }

        finalValue += value;
    }
}

这应该是正确的,但是我不确定它是否足够快(通常SPOJ问题是基于“缓存”数据)