计算数字的尾随零是由因子计算的

时间:2009-07-23 21:11:29

标签: java correctness

我正在尝试计算由阶乘产生的数字的尾随零(意味着数字变得非常大)。下面的代码取一个数字,计算数字的阶乘,并计算尾随零。但是,当数字大约为25!时,numZeros不起作用。

public static void main(String[] args) {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    double fact;
    int answer;

    try {
        int number = Integer.parseInt(br.readLine());
        fact = factorial(number);
        answer = numZeros(fact);
    }
    catch (NumberFormatException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static double factorial (int num) {
    double total = 1;
    for (int i = 1; i <= num; i++) {
        total *= i;
    }
    return total;
}   

public static int numZeros (double num) {
    int count = 0;
    int last = 0;   

    while (last == 0) {
        last = (int) (num % 10);
        num = num / 10;
        count++;
    }

    return count-1;
}

我并不担心这段代码的效率,我知道有很多方法可以提高这段代码的效率。我想弄清楚的是为什么数字大于25的数字尾随零!没有用。

有什么想法吗?

10 个答案:

答案 0 :(得分:17)

您的任务不是计算阶乘而是计算零的数量。一个好的解决方案使用http://en.wikipedia.org/wiki/Trailing_zeros中的公式(您可以尝试证明)

def zeroes(n):
    i = 1
    result = 0
    while n >= i:
        i *= 5
        result += n/i  # (taking floor, just like Python or Java does)
    return result

希望您能将此转换为Java。这只是计算[n / 5] + [n / 25] + [n / 125] + [n / 625] + ...并在除数大于n时停止。

请勿使用BigIntegers。这是一个bozosort。这样的解决方案需要几秒钟才能完成。

答案 1 :(得分:14)

您只需知道产品中有多少2和5。如果你正在计算尾随零,那么你实际上在计算“十分之几除以这个数字?”。如果你代表n!作为q *(2 ^ a)*(5 ^ b)其中q不能被2或5整除。然后在第二个表达式中取a和b的最小值将给出10除以10的次数。实际上进行乘法是过度的。

编辑:计算两个人也是矫枉过正,所以你只需要五个人。

对于某些python,我认为这应该有效:

def countFives(n):
    fives = 0   
    m = 5
    while m <= n:
        fives = fives + (n/m)
        m = m*5
    return fives

答案 2 :(得分:3)

double类型的精度有限,因此如果您使用的数字太大,则double将只是近似值。要解决这个问题,你可以使用像BigInteger这样的东西来使它适用于任意大的整数。

答案 3 :(得分:1)

您可以使用DecimalFormat格式化大数字。如果您通过这种方式格式化数字,那么您将获得scientific notation中的数字,那么每个数字都会像1.4567E7一样,这将使您的工作更轻松。因为E之后的数字 - 后面的字符数。是我认为的尾随零的数量。

我不知道这是否是所需的确切模式。您可以看到如何形成模式here

DecimalFormat formater = new DecimalFormat("0.###E0");

答案 4 :(得分:0)

我的2美分:避免使用double,因为它们容易出错。 在这种情况下,更好的数据类型是BigInteger ,这里有一个小方法可以帮助您:

public class CountTrailingZeroes {

    public int countTrailingZeroes(double number) {
        return countTrailingZeroes(String.format("%.0f", number));
    }

    public int countTrailingZeroes(String number) {
        int c = 0;
        int i = number.length() - 1;

        while (number.charAt(i) == '0') {
            i--;
            c++;
        }

        return c;

    }

    @Test
    public void $128() {
        assertEquals(0, countTrailingZeroes("128"));
    }

    @Test
    public void $120() {
        assertEquals(1, countTrailingZeroes("120"));
    }

    @Test
    public void $1200() {
        assertEquals(2, countTrailingZeroes("1200"));
    }

    @Test
    public void $12000() {
        assertEquals(3, countTrailingZeroes("12000"));
    }

    @Test
    public void $120000() {
        assertEquals(4, countTrailingZeroes("120000"));
    }

    @Test
    public void $102350000() {
        assertEquals(4, countTrailingZeroes("102350000"));
    }

    @Test
    public void $1023500000() {
        assertEquals(5, countTrailingZeroes(1023500000.0));
    }
}

答案 5 :(得分:0)

这是我制作它的方式,但是更大的&gt; 25 factorial长容量是不够的,应该使用Biginteger类,我不熟悉的女巫:)

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Scanner in = new Scanner(System.in);
    System.out.print("Please enter a number : ");
    long number = in.nextLong();
    long numFactorial = 1;

    for(long i = 1; i <= number; i++) {
        numFactorial *= i;
    }
    long result = 0;
    int divider = 5;
    for( divider =5; (numFactorial % divider) == 0; divider*=5) {
         result += 1;
    }

    System.out.println("Factorial of n is: " + numFactorial);
    System.out.println("The number contains " + result + " zeroes at its end.");

    in.close();

 }

}

答案 6 :(得分:0)

对数时间复杂度最好的是:

public int trailingZeroes(int n) {
    if (n < 0)
        return -1;

    int count = 0;
    for (long i = 5; n / i >= 1; i *= 5) {
        count += n / i;
    }

    return count;
}

http://www.programcreek.com/2014/04/leetcode-factorial-trailing-zeroes-java/

无耻地复制

答案 7 :(得分:0)

我在Javascript中解决了同样的问题,我解决了它:

var number = 1000010000;
var str = (number + '').split(''); //convert to string
var i = str.length - 1; // start from the right side of the array
var count = 0; //var where to leave result
for (;i>0 && str[i] === '0';i--){
    count++;
}
console.log(count) // console shows 4

此解决方案为您提供尾随零的数量。

&#13;
&#13;
var number = 1000010000;
var str = (number + '').split(''); //convert to string
var i = str.length - 1; // start from the right side of the	array
var count = 0; //var where to leave result
for (;i>0 && str[i] === '0';i--){
	count++;
}
console.log(count)
&#13;
&#13;
&#13;

答案 8 :(得分:-1)

Java的双倍最大超过9 * 10 ^ 18,其中25!是1.5 * 10 ^ 25.如果你想能够使用高阶因子,你可能想要使用BigInteger(类似于BigDecimal但不做小数)。

答案 9 :(得分:-1)

我写得很快,我觉得它可以准确地解决你的问题。我使用BigInteger类来避免从double转换为整数,可能会导致问题。我在超过25的几个大数字上测试了它,例如101,它准确地返回了24个零。

这种方法背后的想法是,如果你服用25!那么第一次计算是25 * 24 = 600,所以你可以立即关闭两个零,然后做6 * 23 = 138.所以它计算了因子去除零点。

public static int count(int number) {
    final BigInteger zero = new BigInteger("0");
    final BigInteger ten = new BigInteger("10");
    int zeroCount = 0;
    BigInteger mult = new BigInteger("1");
    while (number > 0) {
        mult = mult.multiply(new BigInteger(Integer.toString(number)));
        while (mult.mod(ten).compareTo(zero) == 0){
            mult = mult.divide(ten);
            zeroCount += 1;
        }
        number -= 1;
    }
    return zeroCount;
}

因为你说你根本不关心运行时间(不是我的第一次特别高效,只是稍微多一点)这个只做了阶乘然后计算零,所以它在理论上更简单:

public static BigInteger factorial(int number) {
    BigInteger ans = new BigInteger("1");
    while (number > 0) {
        ans = ans.multiply(new BigInteger(Integer.toString(number)));
        number -= 1;
    }
    return ans;
}

public static int countZeros(int number) {
    final BigInteger zero = new BigInteger("0");
    final BigInteger ten = new BigInteger("10");
    BigInteger fact = factorial(number);
    int zeroCount = 0;
    while (fact.mod(ten).compareTo(zero) == 0){
        fact = fact.divide(ten);
        zeroCount += 1;
    }
}