Project Euler 5 in Python - How can I optimize my solution?

后端 未结 20 894
醉梦人生
醉梦人生 2020-11-30 08:00

I\'ve recently been working on Project Euler problems in Python. I am fairly new to Python, and still somewhat new as a programmer.

In any case, I\'ve ran into a sp

相关标签:
20条回答
  • 2020-11-30 08:33

    I wrote a solution to euler5 that:

    • Is orders of magnitude faster than most of the solutions here when n=20 (though not all respondents report their time) because it uses no imports (other than to measure time for this answer) and only basic data structures in python.
    • Scales much better than most other solutions. It will give the answer for n=20 in 6e-05 seconds, or for n=100 in 1 millisec, faster than most of the responses for n=20 listed here.

      import time
      a=time.clock() # set timer
      
      j=1
      factorlist=[]
      mydict={}
      # change second number to desired number +1 if the question were changed.
      for i in range(2,21,1):
          numberfactors=[]
          num=i
          j=2
      # build a list of the prime factors
          for j in range(j,num+1,1):
              counter=0
              if i%j==0:
                  while i%j==0:
                      counter+=1
                      numberfactors.append(j)
                      i=i/j
      # add a list of factors to a dictionary, with each prime factor as a key
                      if j not in mydict:
                          mydict[j] = counter
      # now, if a factor is already present n times, including n times the factor
      # won't increase the LCM. So replace the dictionary key with the max number of
      # unique factors if and only if the number of times it appears is greater than
      # the number of times it has already appeared.
      # for example, the prime factors of 8 are 2,2, and 2. This would be replaced 
      # in the dictionary once 16 were found (prime factors 2,2,2, and 2).
                  elif mydict[j] < counter:
                      mydict[j]=counter
      
      total=1
      for key, value in mydict.iteritems():
          key=int(key)
          value=int(value)
          total=total*(key**value)
      
      b=time.clock()
      elapsed_time=b-a
      print total, "calculated in", elapsed_time, "seconds"
      

      returns:

      232792560 calculated in 6e-05 seconds
      
      # does not rely on heuristics unknown to all users, for instance the idea that 
      # we only need to include numbers above 10, etc.
      
      
      # For all numbers evenly divisible by 1 through 100:
      69720375229712477164533808935312303556800 calculated in 0.001335 seconds
      
    0 讨论(0)
  • 2020-11-30 08:34

    Break down the number as a prime factorization.

    All primes less than 20 are:

    2,3,5,7,11,13,17,19
    

    So the bare minimum number that can be divided by these numbers is:

    2*3*5*7*11*13*17*19
    

    Composites:

    4,6,8,9,10,12,14,15,16,18,20 = 2^2, 2*3, 2^3, 3^2, 2*5, 2^2*3, 2*7, 3*5, 2*3^2, 2^2*5
    

    Starting from the left to see which factors needed:

    • 2^3 to build 4, 8, and 16
    • 3 to build 9
    • Prime factorization: 2^4 * 3^2 * 5 * 7 * 11 * 13 * 17 * 19 = 232,792,560
    0 讨论(0)
  • 2020-11-30 08:35

    My first answer sped up the original calculation from the question.

    Here's another answer that solves it a different way: just find all the prime factors of each number, then multiply them together to go straight to the answer. In other words, this automates the process recommended by poke in a comment.

    It finishes in a fraction of a second. I don't think there is a faster way to do this.

    I did a Google search on "find prime factors Python" and found this:

    http://www.stealthcopter.com/blog/2009/11/python-factors-of-a-number/

    From that I found a link to factor.py (written by Mike Hansen) with some useful functions:

    https://gist.github.com/weakish/986782#file-factor-py

    His functions didn't do quite what I wanted, so I wrote a new one but used his pull_prime_factors() to do the hard work. The result was find_prime_factors() which returns a list of tuples: a prime number, and a count. For example, find_prime_factors(400) returns [(2,4), (5,2)] because the prime factors of 400 are: (2*2*2*2)*(5*5)

    Then I use a simple defaultdict() to keep track of how many we have seen so far of each prime factor.

    Finally, a loop multiplies everything together.

    from collections import defaultdict
    from factor import pull_off_factors
    
    pf = defaultdict(int)
    
    _primes = [2,3,5,7,11,13,17,19,23,29]
    def find_prime_factors(n):
        lst = []
        for p in _primes:
            n = pull_off_factors(n, p, lst)
        return lst
    
    def find_solution(low, high):
        for num in xrange(low, high+1):
            lst = find_prime_factors(num)
            for n, count in lst:
                pf[n] = max(pf[n], count)
    
        print "prime factors:", pf
        solution = 1
        for n, count in pf.items():
            solution *= n**count
    
        return solution
    
    if __name__ == '__main__':
        solution = find_solution(1, 20)
        print "answer:", solution
    

    EDIT: Oh wow, I just took a look at @J.F. Sebastian's answer to a related question. His answer does essentially the same thing as the above code, only far more simply and elegantly. And it is in fact faster than the above code.

    Least common multiple for 3 or more numbers

    I'll leave the above up, because I think the functions might have other uses in Project Euler. But here's the J.F. Sebastian solution:

    def gcd(a, b):
        """Return greatest common divisor using Euclid's Algorithm."""
        while b:
            a, b = b, a % b
        return a
    
    def lcm(a, b):
        """Return lowest common multiple."""
        return a * b // gcd(a, b)
    
    def lcmm(*args):
        """Return lcm of args."""   
        return reduce(lcm, args)
    
    def lcm_seq(seq):
        """Return lcm of sequence."""
        return reduce(lcm, seq)
    
    solution = lcm_seq(xrange(1,21))
    print "lcm_seq():", solution
    

    I added lcm_seq() but you could also call:

    lcmm(*range(1, 21))
    
    0 讨论(0)
  • 2020-11-30 08:39

    Here is my Python solution, it has 12 iteration so compiled quite fast:

    smallest_num = 1
    for i in range (1,21):
        if smallest_num % i > 0: # If the number is not divisible by i
            for k in range (1,21):
                if (smallest_num * k) % i == 0: # Find the smallest number divisible by i    
                    smallest_num = smallest_num * k
                    break
    print (smallest_num)
    
    0 讨论(0)
  • 2020-11-30 08:40
    import time
    primes = [11,13,17,19]
    composites = [12,14,15,16,18,20]
    
    def evenlyDivisible(target):
        evenly = True
        for n in composites:
            if target % n > 0:
                evenly = False
                break
    return evenly
    
    step = 1
    for p in primes:
        step *= p
    
    end = False
    number = 0
    t1 = time.time()
    while not end:
        number += step
        if evenlyDivisible(number):
            end = True
            print("Smallest positive evenly divisible number is",number)
    t2 = time.time()
    print("Time taken =",t2-t1)
    

    Executed in 0.06 seconds

    0 讨论(0)
  • 2020-11-30 08:41
    up = int(input('Upper limit: '))
    number = list(range(1, up + 1))
    n = 1
    
    for i in range(1, up):
        n = n * number[i]
        for j in range(i):
            if number[i] % number[j] == 0:
                n = n / number[j]
                number[i] = number[i] / number[j]
    print(n)
    
    0 讨论(0)
提交回复
热议问题