2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
Let’s build a more generalized version of it for arbitrary ranges using a) a brute force (BF) approach, b) prime factorization (PF) and c) Julia’s lcm (least common multiple) function:
function reduceDivisors(rangeMin::UInt64, rangeMax::UInt64)
divisorsForRemoval = Array{UInt64,1}();
for i in rangeMax:-1:rangeMin
for j in rangeMax:-1:rangeMin
if i!=j && i!=1 && j!=1 && mod(j,i) ==0 && (i in divisorsForRemoval) == false
push!(divisorsForRemoval,i);
end
end
end
listOfDivisors = collect(rangeMin:rangeMax);
reducedListOfDivisors = setdiff(listOfDivisors, divisorsForRemoval);
return reducedListOfDivisors
end
function getSmallestNumberBF(rangeMin::UInt64, rangeMax::UInt64)
divisors = reduceDivisors(rangeMin, rangeMax);
number::Bool = false;
i::UInt64 = rangeMax; # testing multiples of rangeMax which is the highest number in divisors by definition
while number == false
currentNumber::UInt64 = i;
testResult = Array{UInt64,1}();
for divisor in divisors
push!(testResult, mod(currentNumber, divisor))
end
if sum(testResult) == 0
smallestNumber::UInt64 = currentNumber;
number = true;
return smallestNumber
end
i += rangeMax;
end
end
function isPrime(n::UInt64)
isPrimeNumber::Bool = true;
for i in 2:1:(n-1)
if n%i == 0
isPrimeNumber = false;
return isPrimeNumber
end
end
return isPrimeNumber
end
function getAllPrimes(rangeMax::UInt64)
listOfPrimesInRange = Array{UInt64,1}()
for i in 2:1:rangeMax
if isPrime(i)
push!(listOfPrimesInRange,i);
end
end
return listOfPrimesInRange
end
function primeDecomposition(n::UInt64, listOfPrimesInRange::Array{UInt64,1}, dictOfPrimesInRange::Dict{UInt64,UInt64})
for prime in listOfPrimesInRange
power = 0
while mod(n,prime) == 0
power += 1
n = div(n,prime)
end
if dictOfPrimesInRange[prime] < power
dictOfPrimesInRange[prime] = power
end
end
return dictOfPrimesInRange
end
function getSmallestNumberPF(rangeMin::UInt64, rangeMax::UInt64)
listOfPrimesInRange = getAllPrimes(rangeMax);
dictOfPrimesInRange = Dict{UInt64,UInt64}(i => 0 for i in listOfPrimesInRange);
for i in rangeMin:1:rangeMax
dictOfPrimesInRange = primeDecomposition(i, listOfPrimesInRange, dictOfPrimesInRange);
end
smallestNumber = prod([key^dictOfPrimesInRange[key] for key in keys(dictOfPrimesInRange)]);
return smallestNumber
# lcm is the product of primes with the highest power
end
function JuliaLCM(rangeMin::UInt64,rangeMax::UInt64)
numbers = collect(rangeMin:rangeMax);
leastCommonMultiple = lcm(numbers);
return leastCommonMultiple
end
function parseARGS()
if isempty(ARGS)
rangeMin::UInt64 = 1;
rangeMax::UInt64 = 20;
method::String = "PF";
else
rangeMin = tryparse(UInt64, ARGS[1])
rangeMax = tryparse(UInt64, ARGS[2])
method = ARGS[3]
end
return rangeMin, rangeMax, method
end
function main()
rangeMin, rangeMax, method = parseARGS();
if method == "BF"
smallestNumber = getSmallestNumberBF(rangeMin,rangeMax);
elseif method == "PF"
smallestNumber = getSmallestNumberPF(rangeMin,rangeMax);
else
smallestNumber = JuliaLCM(rangeMin,rangeMax);
end
println(smallestNumber);
end
main()
$ julia ProjectEuler0005.jl 1 10 BF
2520
0.000077 seconds (788 allocations: 53.125 KiB)
$ julia ProjectEuler0005.jl 1 20 BF
232792560
2.534551 seconds (46.56 M allocations: 3.816 GiB, 5.87% gc time)
$ julia ProjectEuler0005.jl 20 30 BF
3605401800
26.114736 seconds (480.72 M allocations: 39.398 GiB, 5.84% gc time)
$ julia ProjectEuler0005.jl 1 10 PF
2520
0.000058 seconds (33 allocations: 1.891 KiB)
$ julia ProjectEuler0005.jl 1 20 PF
232792560
0.000061 seconds (34 allocations: 2.000 KiB)
$ julia ProjectEuler0005.jl 20 30 PF
3605401800
0.000061 seconds (35 allocations: 2.156 KiB)
$ julia ProjectEuler0005.jl 1 10 lcm
2520
0.000045 seconds (21 allocations: 1.109 KiB)
$ julia ProjectEuler0005.jl 1 20 lcm
232792560
0.000045 seconds (21 allocations: 1.188 KiB)
$ julia ProjectEuler0005.jl 20 30 lcm
3605401800
0.000111 seconds (21 allocations: 1.125 KiB)
$ julia ProjectEuler0005.jl 1 34578920 lcm
4934319942519488512
3.981096 seconds (22 allocations: 263.817 MiB, 0.35% gc time)
Using Julia’s lcm is so much more efficient than my quick and dirty implementations. Note: my manual PF approach didn’t reached any result for the range of 1 to 34578920 within 5 minutes.