查找大因子

时间:2016-08-22 06:11:36

标签: java implementation biginteger largenumber

Problem

在上述问题中,给定正整数n,它旨在找到n!中所有数字的总和。所以这是我的java代码:

public static void main (String[] args) throws java.lang.Exception
{

    Scanner sc = new Scanner(System.in);
    while(sc.hasNext())
    {
        int n = sc.nextInt();
        BigInteger b = BigInteger.valueOf(1);
        for(int i=2;i<=n;i++)
            b=b.multiply(BigInteger.valueOf(i));
        String s = b.toString();
        int sum=0;
        for(int i=0;i<s.length();i++)
            sum+=(int)(s.charAt(i)-'0');
        System.out.println(sum);
    }
}

n的限制是n<=1000。它完美无瑕地工作:
INPUT

5
60
100
1000  

输出

3
288
648
10539

但在线评委判断这是一个错误的答案。使用BigInteger课有什么问题吗? 注意:我想在我的程序中实现BigInteger类中的错误,因为此解决方案没有超出时间限制但给出了错误的答案。

2 个答案:

答案 0 :(得分:0)

您的特定情况的一个初始条件是使用Java 8,所以让我们这样做。

首先,如何获得给定输入数的阶乘:

private static final BigInteger TWO = BigInteger.valueOf(2L);

private static BigInteger factorial(final BigInteger inputNumber)
{
    BigInteger ret = BigInteger.ONE;

    BigInteger b = TWO;

    while (b.compareTo(inputNumber) <= 0) {
        ret = ret.multiply(b);
        b = b.add(BigInteger.ONE);
    }

    return ret;
}

然后,从那个号码,如何获得位数?我们使用基数10,因此我们可以使用整数除法和模运算符:

private static int digitSum(final BigInteger someInteger)
{
    int ret = 0;
    BigInteger b = someInteger;
    BigInteger[] modResult;

    while (b.compareTo(BigInteger.ZERO) > 0) {
        modResult = b.divideAndRemainter(BigInteger.TEN);
        ret += modResult[1].intValueExact();
        b = modResult[0];
    }

    return ret;
}

现在,将其插入主程序;你应该从一个文件中读取,该文件的输入是整数,每行一个:

public final class FactDigitSum
{

    // supposes that the two methods above are defined in this class

    private static void printDigitSum(final BigInteger inputNumber)
    {
        final BigInteger factorial = factorial(inputNumber);
        System.out.println(digitSum(factorial));
    }

    // The main program
    public static void main(final String... args)
        throws IOException
    {
        if (args.length == 0)
            throw new IllegalArgumentException("No file as argument");

        final Path path = Paths.get(args[0]);

        try (
            final Stream<String> stream = Files.lines(path);
        ) {
            stream.map(BigInteger::new).forEach(FactDigitSum::printDigitSum);
        }
    }
}

答案 1 :(得分:0)

不要使用字符串。直接从BigInteger计算值。

这应该给你价值。我会把I / O留给你:

public class BigIntFacSum
{
    private static int bigFacSum(final int n)
    {
        int sum = 0;
        BigInteger fac = BigInteger.valueOf(2);
        BigInteger num = BigInteger.valueOf(3);

        for (int i = 3; i <= n; i++)
        {
            fac = fac.multiply(num);
            num = num.add(BigInteger.ONE);
        }

        while (fac.compareTo(BigInteger.ZERO) > 0)
        {
             BigInteger[] quotRem = fac.divideAndRemainder(BigInteger.TEN);
             fac = quotRem[0];
             sum += quotRem[1].intValue();
        }
        return sum;
    }

    public static void main(String[] args)
    {
        System.out.println(bigFacSum(1000));
    }
}

这在Java 7中相当快。在Java 8中应该更快,因为它分别使用 Karatsuba Burnikel-Ziegler 优化进行乘法和除法(如据我所知,Java 7没有。)

对于它的价值:如果数字变大,可能通过字符串绕行然后添加字符串中的数字变得更快。在循环中使用divideAndRemainder(BigInteger.TEN)的天真方式对于像100000!这样的大数字不适用。我用我自己的BigInteger实现(用不同的语言)尝试了这个,并且字符串绕行对于这样的巨大的nubmers来说要快得多。这是因为使用分而治之算法高度优化了转换为十进制,并且比天真循环更快。但仅限于相对较大的数字,即远远超过10000!。 AFAIK,Java使用类似的算法,因此转换为字符串也应该更快,对于类似的大型数据库。

我不知道一种分而治之的算法,它同时计算数字的总和,虽然我不明白它为什么不能。但算法并不简单,mine is not in Java

但是,这只是作为一个旁边,以防你或其他任何人可能需要这一天。