def eratosthenes_sieve(n):
    """
    Sieve of Eratosthenes
    Complexity: O(NloglogN)

    We can find all the prime number up to specific
    point. This technique is based on the fact that
    the multiples of a prime number are composite numbers.
    That happens because a multiple of a prime number will
    always have 1, itself and the prime as a divisor (maybe
    even more) and thus, it's not a prime number. A common
    rule for sieves is that they have O(logN) complexity.
    """
    primes = [True] * (n+1)
    primes[0] = False
    primes[1] = False
    for i in range(2, int(n**0.5) + 1):
        if primes[i]:
            for j in range(i*i, n+1, i):
                primes[j] = False

    final_primes = []
    for i in range(len(primes)):
        if primes[i]:
            final_primes.append(i)

    return final_primes