简体   繁体   中英

Code finding the first triangular number with more than 500 divisors will not finish running

Okay, so I'm working on Euler Problem 12 (find the first triangular number with a number of factors over 500) and my code (in Python 3) is as follows:

factors = 0
y=1

def factornum(n):
    x = 1
    f = []
    while x <= n:
        if n%x == 0:
            f.append(x)
        x+=1
    return len(f)

def triangle(n):
    t = sum(list(range(1,n)))
    return t

while factors<=500:
    factors = factornum(triangle(y))
    y+=1

print(y-1)

Basically, a function goes through all the numbers below the input number n, checks if they divide into n evenly, and if so add them to a list, then return the length in that list. Another generates a triangular number by summing all the numbers in a list from 1 to the input number and returning the sum. Then a while loop continues to generate a triangular number using an iterating variable y as the input for the triangle function, and then runs the factornum function on that and puts the result in the factors variable. The loop continues to run and the y variable continues to increment until the number of factors is over 500. The result is then printed.

However, when I run it, nothing happens - no errors, no output, it just keeps running and running. Now, I know my code isn't the most efficient, but I left it running for quite a bit and it still didn't produce a result, so it seems more likely to me that there's an error somewhere. I've been over it and over it and cannot seem to find an error.

I'd merely request that a full solution or a drastically improved one isn't given outright but pointers towards my error(s) or spots for improvement, as the reason I'm doing the Euler problems is to improve my coding. Thanks!

You have very inefficient algorithm.

If you ask for pointers rather than full solution, main pointers are:

  1. There is a more efficient way to calculate next triangular number . There is an explicit formula in the wiki. Also if you generate sequence of all numbers it is just more efficient to add next n to the previous number. (Sidenote list in sum(list(range(1,n))) makes no sense to me at all. If you want to use this approach anyway, sum(xrange(1,n) will probably be much more efficient as it doesn't require materialization of the range)

  2. There are much more efficient ways to factorize numbers

  3. There is a more efficient way to calculate number of factors. And it is actually called after Euler: see Euler's totient function

Generally Euler project problems (as in many other programming competitions) are not supposed to be solvable by sheer brute force. You should come up with some formula and/or more efficient algorithm first.

As far as I can tell your code will work, but it will take a very long time to calculate the number of factors. For 150 factors, it takes on the order of 20 seconds to run, and that time will grow dramatically as you look for higher and higher number of factors.

One way to reduce the processing time is to reduce the number of calculations that you're performing. If you analyze your code, you're calculating n%1 every single time, which is an unnecessary calculation because you know every single integer will be divisible by itself and one. Are there any other ways you can reduce the number of calculations? Perhaps by remembering that if a number is divisible by 20, it is also divisible by 2, 4, 5, and 10?

I can be more specific, but you wanted a pointer in the right direction.

From the looks of it the code works fine, it`s just not the best approach. A simple way of optimizing is doing until the half the number, for example. Also, try thinking about how you could do this using prime factors, it might be another solution. Best of luck!

First you have to def a factor function:

from functools import reduce

def factors(n):
    step = 2 if n % 2 else 1
    return set(reduce(list.__add__,
                  ([i, n//i] for i in range(1, int(pow(n,0.5) + 1)) if n % i 
== 0)))

This will create a set and put all of factors of number n into it.

Second, use while loop until you get 500 factors:

a = 1
x = 1
while len(factors(a)) < 501:
    x += 1
    a += x

This loop will stop at len(factors(a)) = 500. Simple print(a) and you will get your answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM