I'm doing Project Euler to learn Clojure.
The purpose of this function is to calculate the lcm of the set of integers from 1
to m
.
(lcm 10)
returns 2520
This is a rather brute-force way of doing this. In theory, we go through each number from m
to infinity and return the first number for which all values 1
through m
divide that number evenly.
If I understand what 'lazy' means correctly (and if I am truly being lazy here), then this should run in constant space. There's no need to hold more than the list of numbers from 1
to m
and 1 value from the infinite set of numbers that we're looping through.
I am, however, getting a java.lang.OutOfMemoryError: Java heap space
at m
values greater than 17.
(defn lcm [m]
(let [xs (range 1 (+ m 1))]
(first (for [x (iterate inc m) :when
(empty?
(filter (fn [y] (not (factor-of? y x))) xs))] x))))
Thanks!
Constant space is the one that is fixed for that algorithm, generally equals to space used by input and local variables. Auxiliary Space is the extra/temporary space used by an algorithm.
O(1) Complexity: We consider constant space complexity when the program doesn't contain any loop, recursive function, or call to any other functions.
We can clearly see that the space complexity is constant, so, it can be expressed in big-O notation as O(1). Again, let's list all variables present in the above code: array – the function's only argument – the space taken by the array is equal 4n bytes where n is the length of the array. size – a 4-byte integer.
Note that the big-O expressions do not have constants or low-order terms. This is because, when N gets large enough, constants and low-order terms don't matter (a constant-time algorithm will be faster than a linear-time algorithm, which will be faster than a quadratic-time algorithm).
As far as I can tell, your code is in fact lazy (also in the sense that it's in no hurry to reach the answer... ;-) -- see below), however it generates piles upon piles upon piles of garbage. Just consider that (lvm 17)
amounts to asking for over 1.2 million lazy filtering operations on (range 1 18)
. I can't reproduce your out-of-memory problem, but I'd tentatively conjecture it might be an issue with your memory & GC settings.
Now although I realise that your question is not actually about algorithms, note that the production of all that garbage, the carrying out of all those filtering operations etc. not only utterly destroy the space complexity of this, but the time complexity as well. Why not use an actual LCM algorithm? Like the one exploiting lcm(X) = gcd(X) / product(X)
for X
a set of natural numbers. The GCD can be calculated with Euclid's algorithm.
(defn gcd
([x y]
(cond (zero? x) y
(< y x) (recur y x)
:else (recur x (rem y x))))
([x y & zs]
(reduce gcd (gcd x y) zs)))
(defn lcm
([x y] (/ (* x y) (gcd x y)))
([x y & zs]
(reduce lcm (lcm x y) zs)))
With the above in place, (apply lcm (range 1 18))
will give you your answer in short order.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With