错误的结果是更大的价值观

时间:2016-02-04 15:56:05

标签: java algorithm

我正在尝试编程问题,声明是 如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23.像这样我们必须找到'的倍数之和。吨'测试用例' n'每个值,我试图找到解决方案,我的代码是

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class Solution {

    public static void main(String[] args) {

        long t,n,sum;
        Scanner in=new Scanner(System.in);
        t=in.nextLong();
        for(int i=0;i<t;i++)
        {
            sum=0;
            n=in.nextLong();
            long l3=0,l5=0,l15=0;
            for(int j=3;j>0;j--)
                if((n-j)%3==0&&j<n)
                {
                l3=n-j;
                break;
            }
            for(int j=5;j>0;j--)
                if((n-j)%5==0&&j<n)
                {
                l5=n-j;
                break;
            }
            for(int j=15;j>0;j--)
                if((n-j)%15==0&&j<n)
                {
                l15=n-j;
                break;
            }

            sum+=(float)(((float)l3/(float)3)/(float)2)*(float)(l3+3);

            sum+=(float)(((float)l5/(float)5)/(float)2)*(float)(l5+5);

            sum-=(float)(((float)l15/(float)15)/(float)2)*(float)(l15+15);
            System.out.println(sum);    

        }
    }
} 

我提供的输入是,

12
10
11
12
13
1000
1001
1002
1003
100000000
100000001
100000002
100000003

这里有12个测试用例的数量。

我得到的输出是

23
33
33
45
233168
234168
234168
235170
2333333593784320
2333333593784320
2333333593784320
2333333593784320

这里的问题是对于测试用例10,11,12,13,1000,1001,1002,1003中的值,答案是正确的,但输出对于剩余的较大输入是错误的。我找不到我错过的东西。你能帮我解释一下为什么我会得到这种错误的结果以及如何纠正它。

4 个答案:

答案 0 :(得分:1)

如果没有对代码进行更深入的分析,我猜测问题就是你使用浮点数,它的值范围非常短。你可以尝试双倍吗?不确定答案是什么,但至少你会得到不同的结果(我刚试过)

答案 1 :(得分:1)

对于这样的任务,解决方案看起来太复杂了。我不明白你为什么要在最后执行分工。您可以尝试以下代码:

int t = <some number> // the upper bound
int[] dividers = [...] // those are divisors against which we have to test
long sum = 0;
// check all the number up the bound
for (int number = 1; number < t; number++) {
    for (int i = 0; i < dividers.length; i++) {
        if (number % dividers[i] == 0) {
             // the number is divisible without remainder -> add it to the sum
             sum += number;
             break;
        }
    }    
}

这个想法是迭代你要检查的所有数字,看看它们是否可以被一些N分频器整除。如果找到一个数字,则将其添加到总和中并继续下一个数字。

修改 在OP的澄清之后,我提出了另一种方法来做到这一点。

int t = <some number> // the upper bound
int dividers = [3, 5];
int dividerProduct = dividers[0] * dividers[1];
long sum = calculateSumForDivider(dividers[0], t) + calculateSumForDivider(dividers[1], t) - calculateSumForDivider(dividerProduct, t);

public static int calculateSumForDivider(int divider, int number) {
    int n = number / divider;
    return divider * n * (n + 1) / 2;
}

这一切背后的逻辑是什么? 通过除以目标数,我们可以计算分配器在目标中“适合”的次数。这也是区间[1,数字]中可被除法器整除的数字数。我们来看一个例子:

t = 10, divider = 3
10 / 3 = 3, so they are 3 numbers in the interval [1, 10], divisible by 3
the numbers are: 1 * 3, 2 * 3, 3 * 3
if we calculate the sum we get 1 * 3 + 2 * 3 + 3 * 3 = 3 * (1 + 2 + 3) = 18

analogically, for = 10, divider = 5
10 / 5 = 2
1 * 5 + 2 * 5 = 5 * (1 + 2) = 15

作为结论,我们总结了以下公式:

sum = divider * n * (n + 1) / 2

其中n是除法的结果。

这里的问题是,可以被3和5整除的数字(换句话说可被15整除)将被加到两次总和中。为了纠正这个问题,我们使用与上面相同的公式来计算它们的总和,并从得到的总和中减去它,得到结果。

此解决方案仅适用于2个分隔符,因为多个将多次添加到总和的数字将以指数方式增长。 F.E.如果我们想要分为3,4或5,我们将需要照顾12,15,20,60等。

如果两个分频器是另一个分频器的功率,如3和9,这也行不通。在这种情况下,我们只需要可被3整除的数字。

答案 2 :(得分:1)

使用BigDecimal和BigInteger可以获得更高的精度和更大的数字:

package test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;

public class Solution {

    public static void main(String[] args) {

        long t,n;
        BigInteger sum;
        Scanner in=new Scanner(System.in);
        t=in.nextLong();
        for(int i=0;i<t;i++)
        {
            sum = BigInteger.ZERO;
            n=in.nextLong();
            long l3=0,l5=0,l15=0;
            for(int j=3;j>0;j--)
                if((n-j)%3==0&&j<n)
                {
                    l3=n-j;
                    break;
                }
            for(int j=5;j>0;j--)
                if((n-j)%5==0&&j<n)
                {
                    l5=n-j;
                    break;
                }
            for(int j=15;j>0;j--)
                if((n-j)%15==0&&j<n)
                {
                    l15=n-j;
                    break;
                }

            BigDecimal x = BigDecimal.valueOf(l3)
            .divide(BigDecimal.valueOf(6))
            .multiply(BigDecimal.valueOf(l3+3));
            sum=sum.add(x.toBigIntegerExact());
            x = BigDecimal.valueOf(l5)
            .divide(BigDecimal.valueOf(10))
            .multiply(BigDecimal.valueOf(l5+5));
            sum=sum.add(x.toBigIntegerExact());
            x = BigDecimal.valueOf(l15)
            .divide(BigDecimal.valueOf(30))
            .multiply(BigDecimal.valueOf(l15+15));
            sum=sum.subtract(x.toBigIntegerExact());

            System.out.println(sum);    
        }
    }
} 

答案 3 :(得分:0)

我不确定你的算法,因为最简单的算法应该是:

 sum=0;
     n=100100000;

     for(int j=1;j<n;j++)
         if(j%3==0 || j%5==0)
         {
             sum+=j;
         }
     System.out.println(sum);   
     System.out.println(n*n);  

为了更好地了解结果应该是什么,它总是小于n*n

我找到的输出是:

2338002249916668
10020010000000000

因此,如果你的结果小于n*n,如果你确定你的算法,那么它们是正确的。