Calkin Wilf Sequence on codefights

Category: programming


Codefights is a website for practicing and brushing up on programming skills. Recently I have been working on its Python arcade, trying to learn more Python language special features. Well, generally I think most questions are well-thought but are not problems for me – I am confident about my knowledge of Python so far. However, I did get stuck on one question in the generator section.

To be honest, I have not get the coroutine based generator thing inside out yet but this question: Calkin Wilf Sequence surely does not require that sort of knownledge but just generators – and I got TLE – time limit exceeded error. So I checked for a few parts to improve the effeciency but I still got TLE.

The version goes like:

def calkinWilfSequence(number):
    def fractions():
        from collections import deque
        res = deque([(1, 1)])
        while True:
            ret = res.popleft()
            yield list(ret)
            a, b = ret
            c = a + b
            res.append((a, c))
            res.append((c, b))

    gen = fractions()
    res = 0
    while next(gen) != number:
        res += 1
    return res

Using deque, using tuple over lists, well, there are not other good suggestions that I can think of. So it must have something to do with the algorithm itself.

After Googling, I found Calkin Wilf Tree on wikipedia and turns out there is a formula for it and the improved version becomes:

def calkinWilfSequence(number):
    def fractions():
        curr, prev = [1, 1], None
        while True:
            yield curr
            prev = curr
            curr = [prev[1], 2 * prev[1] * int(prev[0] / prev[1]) - prev[0] + prev[1]]

    gen = fractions()
    res = 0
    while next(gen) != number:
        res += 1
    return res

And I timed the different versions, first time on my own PC with 8GB of memory:

In [3]: %timeit calkinWilfSequence([20, 1])
2.2 s ± 2.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [4]: %timeit calkinWilfSequence2([20, 1])
1.78 s ± 23 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Then on a desktop with 32GB of memory:

In [3]: %timeit calkinWilfSequence([20, 1])
524 ms ± 24.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [4]: %timeit calkinWilfSequence2([20, 1])
536 ms ± 24.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

So when memory is not a problem, getting rid of those math caculation can help a bit it seems but if the memory is indeed an issue, then the improved version is indeed the winner.