2016-04-08 18 views
1

Bir sayının tek sayılı veya çift sayıdaki bölen sayısına sahip olup olmadığını belirlemek için aşağıdaki kodu bir araya getirdim. Kod nispeten küçük sayılarla iyi çalışır, ancak 9 rakam gibi daha büyük bir sayı girildiğinde kilitlenir.Daha az bellek kullanarak hesaplamalarımı gerçekleştirmek için Python kodumu nasıl optimize edebilirim?

def divisors(n): 
    num = len(set([x for x in range(1,n+1) if not divmod(n,x)[1]])) 
    if (num != 0 and num % 2 == 0): 
     return 'even' 
    else: 
     return 'odd' 

Bunu daha verimli hale getirmek için ne yapabilirim?

+0

Ayrıca bkz. Http://stackoverflow.com/questions/171765/what-is-the-best-way-to-get-all-the-divisors-of-a-number veya http://stackoverflow.com/questions/12421969/find-all-divisors-of-a-number-optimization –

cevap

2

İşte senin sorunun: o zaman, bu bir liste oluşturur

num = len(set([x for x in range(1,n+1) if not divmod(n,x)[1]])) 

bu listenin dışında bir dizi oluşturur, daha sonra setin uzunluğu alır. Bu işin hiçbirini (range(), veya xrange(), ya da xrange(), yinelenen nesneler üretmez yapmanıza gerek yoktur; bu nedenle, sete ihtiyacımız yoktur ve sum(), yinelenen herhangi bir nesne üzerinde çalışır; ya da. Konuyla ilgili olduğumuzda, sadece n % x'u yazmanın çok ayrıntılı bir yoludur ve bir tuple oluşturmak için biraz daha fazla bellek tüketir (bu da tuple'ı attığınız için hemen geri alınır). İşte sabit sürümü: Sen (n) sqrt kadar test olası her böleni test etmek gerekmez

num = sum(1 for x in xrange(1,n+1) if not n % x) 
2

yeterlidir. Bu, O (n) yerine O (sqrt (n)) işlevinizi gerçekleştirecektir. python2 kullanarak testlerde ise

import math 

def num_divisors(n): 
    sqrt = math.sqrt(n) 
    upper = int(sqrt) 
    num = sum(1 for x in range(1, upper + 1) if not n % x) 
    num *= 2 
    if upper == sqrt and num != 0: 
     num -= 1 
    return num 

bu 1000 kat daha hızlı sum(1 for x in range(1, n + 1) if not n % x) daha n = int(1e6) ve 10000 kat daha hızlı 1E8 için beraberdir. 1e9 için, bu ikinci kod bananumaralı bir bellek hatası verdi, bu da tüm dizinin toplamını yapmadan önce bellekte saklandığını gösteriyor, çünkü python 2 range()'da bir liste döndürüyor ve bunun yerine xrange() kullanmalıyım. Python3 için range() iyi.

+0

'range()' yerine 'xrange()' işlevini kullanmamı hatırlattığınız için teşekkür ederiz. – Kevin

+0

Gizem çözüldü! – Goyo

İlgili konular