1

I decided to try out Sieve of Eratosthenes to find the list of primes less or equal to N. Here is my solution:

def findPrimeN(num):
    result = []
    multiples = []
    for i in range(2, num+1):
        if i not in multiples:
            result.append(i)
        for j in range(i*i, num+1, i):
            multiples.append(j)
    return result

It is not immediately clear what my run time is, I would guess O(n^2), but is the inner loop really using O(n)? Moreover, that if i not in multiples: might also be O(n), but I am not familiar with python implementation of not in list.

Second part of my question is how to optimize it? I saw some solutions using set or collector, but do they really provide better run time like O(1) due to look up table?

Thanks!

return 0
  • 4,226
  • 6
  • 47
  • 72
  • 2
    Sets will, in fact, provide much better run-time than linearly searching through lists. OTOH, once you have working code, CodeReview might be a better site than StackOverflow – Patrick Maupin Sep 26 '15 at 04:19
  • 2
    This may be a better candidate for codereview.stackexchange. One thing I noticed is that if i is in multiples, then all of its multiples will already be in that list. You should skip the multiples.append in that case. And yes, you should use sets. [`x in alist` has O(n) runtime; `x in aset` has O(1).](https://wiki.python.org/moin/TimeComplexity). – kojiro Sep 26 '15 at 04:20
  • 2
    i think this is a solved problem im sure you can find the optimal solution with a simple google search – Joran Beasley Sep 26 '15 at 04:29
  • Typically, a Sieve of Eratosthenes would use an array of flags to determine primality with lower memory requirements, not a list or set of primes found so far. With Python builtins, you could construct the initial array of flags with just `flags = bytearray(b'\x01') * (num + 1)`. Even though look up in a set is `O(1)`ish, the access patterns and fixed overhead is a lot higher than checking flags in a `bytearray`. The `bytearray` is wasting 7 out of every 8 bits, but it's still cheaper than storing `set`s of Python `int`s. – ShadowRanger Sep 26 '15 at 04:32
  • 1
    Yes (in fact, you can do much better than that; my personal Sieve uses one byte to store primality of a block of 30 numbers), but when implementing in Python, the cost of bitwise operations is a lot higher than in other languages; unless you really *need* to sieve high enough that memory starts running out, it's not worth it. – ShadowRanger Sep 26 '15 at 04:48
  • not sure what you runtime complexity is? [estimate it empirically!](https://en.wikipedia.org/wiki/Analysis_of_algorithms#Empirical_orders_of_growth) – Will Ness Sep 29 '15 at 17:15
  • @ShadowRanger +1 for "my personal Sieve" – C8H10N4O2 Dec 07 '16 at 15:44
  • @C8H10N4O2: Heh. When I was in college, one of the personal exercises I used to gauge my progress on learning to program was writing a better exhaustive prime number generation routine (that is, how fast could I identify all primes from 2 to n, and how large an `n` could I support). My personal sieve (C, w/Python interface) hard codes the primes from 1-30, then sieves the rest with bit flags. Since there are exactly 8 possible primes modulo 30 for each range of `30n` to `30(n + 1)` for all `n >= 1` (you subtract all numbers that are divisible by 2, 3 and 5), each byte represents a block of 30. – ShadowRanger Dec 07 '16 at 16:06
  • Means it can exhaustively sieve up to ~128.8 billion on 4 GB of RAM (takes a few minutes to do so of course; don't recall exact timing, but it's within a reasonable range; program allows you to store the final flag bytes to a file, so you can pay the generation cost once and then it's just a simple memory map and bit twiddling to get the values the second time). :-) – ShadowRanger Dec 07 '16 at 16:08

1 Answers1

0

This is the solution which is O(Nlog(N)).For lookup in O(1) we use flag array so that if flag[i]==0 this means i is prime.Earlier we assume all numbers as primes.Now we loop to eliminate its multiples by setting its multiples(j) ( flag[j]=1 ).

import math
N = 25
flag = [0]*(N+1) # if flag[i] = 0 then i is primes else not

# we are only considering odd numbers because only even prime is 2
# We are considering a fact that one factor( >1 ) of i<N must be <= sqrt(N) if it is not prime

for i in range(3,int(math.sqrt(N))+1,2): 
    if flag[i]==0:
        for j in range( 3*i, N+1, 2*i):   #setting only odd multiples = 1, this loop runs for O(N/i) times
            flag[j]=1

primes = [2]
for i in range(3,len(flag),2):
    if flag[i]==0:
        primes.append(i)

for i in primes: print i

"""
Time complexity 
                <=sum( N/i ) i=3, 5, 7 ..N
                <= sum( N/i ) i=1,2,3...N
                <= O( Nlog(N) )
"""
Ankit Vallecha
  • 708
  • 7
  • 17
  • 1
    This doesn't really answer the question... the question was "what's the runtime of my solution?" This answer is "here let me paste another solution and tell you its runtime" – C8H10N4O2 Dec 07 '16 at 15:50