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.
v = 1
p_i
in primes less than or equal to N
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
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.