简体   繁体   中英

Program using loops for math purpose. (Java)

Let me explain the problem.

I need to write a program where I enter a number N and, then I must find the minimum number divisible by all the numbers down to one.

Eg:. If my N is 5, the answer would be 60. 60 is divisible by 5, 4, 3, 2 and 1.

Here is what I have so far...

import java.util.Scanner;

public class Questão_04 {
public static void main (String [] args)
{
    int x = 1, n = 1, d = x % n;

    System.out.print("Enter N: ");

    Scanner in = new Scanner(System.in);

    n = in.nextInt();

    do
    {
        if (d != 0)
        {
            x = x + 1;
            do
            {
                n = n -1;                   
            } while (n != 0);
        }
        else
        {
            do
            {
                n = n - 1;
            } while (d != 0);
        }

    } while (n != 0);

    System.out.print(x);\\the minimum number divisible by N and all up to N.

} 

Finally, after racking my brain for some time, i finally found an efficient solution:

public int smallestMatching(int n){
    ArrayList<Integer> divisors = new ArrayList<>();

    for(int i = 2 ; i <= n ; i++){
        int tmp = i;

        //simplify div, until it can't be created by multiplying elements of divisors
        for(int div : divisors)
            if(tmp % div == 0)
                tmp /= div;

        if(tmp != 1) 
        //tmp cant be generated from number that are content of divisors
        //-> add to divisors
        {
            divisors.add(tmp);
        }
    }

    //calculate the final result
    int result = 1;
    for(int div: divisors)
        result *= div;

    return result;
}

Love that question :D.

An efficient algorithm for finding this value considers only the prime powers less than or equal to N.

  • start with v = 1
  • for p_i in primes less than or equal to N
    • find maximum integer q_i such that p_i ^ q_i <= N
    • v *= p_i ^ q_i

For you example N=5, the primes are 2,3,5 and

  • 2^2 = 4 < 5 < 2^3
  • 3^1 = 3 < 5 < 3^3
  • 5^1 = 5 = 5 < 5^2

So v = 2^2 * 3 * 5 = 60

For N = 18, you end up with

v = 2^4 * 3^2 * 5 * 7 * 11 * 13 * 17

The only tricky bit is the generation of the primes less than N.

However since v grows very quickly as N increases ( O(N!) or O(N^log(N)) or something like that) you will overflow integer (or even long) arithmetic, at some low value of N (in the hundreds maybe?) This means you can probably get away with precalculating a small table of primes. (Unless you're using an arbitrary precision numerical type)

I guess you're trying to calculate f(n) = lcm(1,2,...,n) . The function seems to grow rapidly for small n , though it may eventually taper off as the primes space out, I suppose. Theory says ln f(n)/n is asymptotic to 1 , so f(n) grows roughly exponentially.

We can simplify by noting lcm(1,2,...,n) = lcm(lcm(1,2,...,n-1),n) , so f(n) can be computed recursively. Furthermore, lcm(a,b) = a*b/gcd(a,b) so we can write the recursion in terms of the standard gcd function. I suggest calculating f recursively as follows: f(n+1) = f(n) / gcd(f(n),n+1) * (n+1) . Dividing before multiplying keeps the size of intermediate results small. The gcd divides f(n) evenly so integer division is fine. You can speed up the calculation by memoizing the f(n) though it won't help if you're only calculating f(n) for one n .

I've implemented the function in Java below. It runs as fast as I can hit , at least until stack size overflows, around n=10000 on my computer. You can reorganize to use iteration instead of recursion, which might push the maximum n higher. (I guess it runs out of memory around n=50000 on my computer based on similar situations, but I haven't actually tried it.)

import java.math.BigInteger;

public class LCM {
  public static BigInteger f(int n) {
    if (n == 1) return BigInteger.ONE;
    BigInteger prev = f(n-1);
    return prev.divide(prev.gcd(BigInteger.valueOf(n)))
      .multiply(BigInteger.valueOf(n));
  }

  public static void main(String[] args) {
    int n = Integer.parseInt(args[0]);
    System.out.println("f(" + n + ") = " + f(n));
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM