获得所有除数的最佳方法是什么?

时间:2008-10-05 09:48:58

标签: python algorithm math

这是非常愚蠢的方式:

def divisorGenerator(n):
    for i in xrange(1,n/2+1):
        if n%i == 0: yield i
    yield n

我想得到的结果与此类似,但我想要一个更聪明的算法(这个太慢而且笨: - )

我可以足够快地找到素因子及其多样性。 我有一个以这种方式生成因子的生成器:

(factor1,multiplicity1)
(factor2,multiplicity2)
(factor3,multiplicity3)
等等...

即。

的输出
for i in factorGenerator(100):
    print i

是:

(2, 2)
(5, 2)

我不知道这对我想要做的事情有多大(我将其编码为其他问题),无论如何我想要一个更聪明的方法来制作

for i in divisorGen(100):
    print i

输出:

1
2
4
5
10
20
25
50
100

更新:非常感谢Greg Hewgill和他的“聪明方式”:) 计算所有除数为100000000的时间为0.01s,他的方式与我在机器上愚蠢的方式相比,非常酷:D

更新2:停止说这是this帖子的副本。计算给定数的除数数不需要计算所有除数。这是一个不同的问题,如果你认为它不是在维基百科上寻找“除数函数”。在发布之前阅读问题和答案,如果你不明白什么是主题,就不要添加没有用的,已经给出答案。

17 个答案:

答案 0 :(得分:70)

鉴于您的factorGenerator函数,这里有一个divisorGen应该可以工作:

def divisorGen(n):
    factors = list(factorGenerator(n))
    nfactors = len(factors)
    f = [0] * nfactors
    while True:
        yield reduce(lambda x, y: x*y, [factors[x][0]**f[x] for x in range(nfactors)], 1)
        i = 0
        while True:
            f[i] += 1
            if f[i] <= factors[i][1]:
                break
            f[i] = 0
            i += 1
            if i >= nfactors:
                return

该算法的整体效率完全取决于factorGenerator的效率。

答案 1 :(得分:33)

为了扩展Shimi所说的内容,你应该只运行从1到n的平方根的循环。然后找到这对,做n / i,这将涵盖整个问题空间。

如前所述,这是一个NP,或“困难”的问题。穷举搜索,你正在做的方式,就像保证答案一样好。加密算法等使用这一事实来帮助保护它们。如果有人要解决这个问题,那么大多数(如果不是全部)当前的“安全”通信都会变得不安全。

Python代码:

import math

def divisorGenerator(n):
    large_divisors = []
    for i in xrange(1, int(math.sqrt(n) + 1)):
        if n % i == 0:
            yield i
            if i*i != n:
                large_divisors.append(n / i)
    for divisor in reversed(large_divisors):
        yield divisor

print list(divisorGenerator(100))

哪个应输出如下列表:

[1, 2, 4, 5, 10, 20, 25, 50, 100]

答案 2 :(得分:14)

我认为你可以停在math.sqrt(n)而不是n / 2。

我会举例说明你可以轻松理解它。现在sqrt(28)5.29所以ceil(5.29)将为6.所以如果我将在6点停止,那么我将获得所有除数。怎么样?

首先看代码,然后看图像:

import math
def divisors(n):
    divs = [1]
    for i in xrange(2,int(math.sqrt(n))+1):
        if n%i == 0:
            divs.extend([i,n/i])
    divs.extend([n])
    return list(set(divs))

现在,请看下图:

假设我已将1添加到我的除数列表中,并从i=2开始,所以

Divisors of a 28

所以在所有迭代结束时,因为我已将商和除数添加到我的列表中,所有28的除数都被填充。

来源:How to determine the divisors of a number

答案 3 :(得分:13)

虽然已经有很多解决方案,但我真的要发布这个:)

这是:

  • 可读
  • 自包含,复制&amp;准备就绪
  • 快速(在有很多素因子和除数的情况下,比接受的解决方案快10倍)
  • python3,python2和pypy compliance

代码:

def divisors(n):
    # get factors and their counts
    factors = {}
    nn = n
    i = 2
    while i*i <= nn:
        while nn % i == 0:
            factors[i] = factors.get(i, 0) + 1
            nn //= i
        i += 1
    if nn > 1:
        factors[nn] = factors.get(nn, 0) + 1

    primes = list(factors.keys())

    # generates factors from primes[k:] subset
    def generate(k):
        if k == len(primes):
            yield 1
        else:
            rest = generate(k+1)
            prime = primes[k]
            for factor in rest:
                prime_to_i = 1
                # prime_to_i iterates prime**i values, i being all possible exponents
                for _ in range(factors[prime] + 1):
                    yield factor * prime_to_i
                    prime_to_i *= prime

    # in python3, `yield from generate(0)` would also work
    for factor in generate(0):
        yield factor

答案 4 :(得分:7)

我喜欢Greg解决方案,但我希望它更像python。 我觉得它会更快,更具可读性; 所以经过一段时间的编码后,我就出来了。

制作列表的笛卡尔积所需要前两个函数。 并且只要出现这个问题就可以重复使用。 顺便说一句,我必须自己编程,如果有人知道这个问题的标准解决方案,请随时与我联系。

“Factorgenerator”现在返回一个字典。然后将字典输入“除数”,使用它来首先生成列表列表,其中每个列表是具有p prime的形式p ^ n的因子列表。 然后我们制作这些列表的笛卡尔积,我们最终使用Greg的解决方案来生成除数。 我们对它们进行排序,并将它们归还。

我测试了它,它似乎比以前的版本快一点。我测试它是一个更大的程序的一部分,所以我不能说它有多快它。

Pietro Speroni(pietrosperoni点吧)

from math import sqrt


##############################################################
### cartesian product of lists ##################################
##############################################################

def appendEs2Sequences(sequences,es):
    result=[]
    if not sequences:
        for e in es:
            result.append([e])
    else:
        for e in es:
            result+=[seq+[e] for seq in sequences]
    return result


def cartesianproduct(lists):
    """
    given a list of lists,
    returns all the possible combinations taking one element from each list
    The list does not have to be of equal length
    """
    return reduce(appendEs2Sequences,lists,[])

##############################################################
### prime factors of a natural ##################################
##############################################################

def primefactors(n):
    '''lists prime factors, from greatest to smallest'''  
    i = 2
    while i<=sqrt(n):
        if n%i==0:
            l = primefactors(n/i)
            l.append(i)
            return l
        i+=1
    return [n]      # n is prime


##############################################################
### factorization of a natural ##################################
##############################################################

def factorGenerator(n):
    p = primefactors(n)
    factors={}
    for p1 in p:
        try:
            factors[p1]+=1
        except KeyError:
            factors[p1]=1
    return factors

def divisors(n):
    factors = factorGenerator(n)
    divisors=[]
    listexponents=[map(lambda x:k**x,range(0,factors[k]+1)) for k in factors.keys()]
    listfactors=cartesianproduct(listexponents)
    for f in listfactors:
        divisors.append(reduce(lambda x, y: x*y, f, 1))
    divisors.sort()
    return divisors



print divisors(60668796879)

P.S。 这是我第一次发布到stackoverflow。 我期待着任何反馈。

答案 5 :(得分:2)

改编自CodeReview,这是一个适用于num=1

的变体
from itertools import product
import operator

def prod(ls):
   return reduce(operator.mul, ls, 1)

def powered(factors, powers):
   return prod(f**p for (f,p) in zip(factors, powers))


def divisors(num) :

   pf = dict(prime_factors(num))
   primes = pf.keys()
   #For each prime, possible exponents
   exponents = [range(i+1) for i in pf.values()]
   return (powered(primes,es) for es in product(*exponents))

答案 6 :(得分:1)

老问题,但这是我的看法:

def divs(n, m):
    if m == 1: return [1]
    if n % m == 0: return [m] + divs(n, m - 1)
    return divs(n, m - 1)

您可以代理:

def divisorGenerator(n):
    for x in reversed(divs(n, n)):
        yield x

注意:对于支持的语言,这可能是尾递归。

答案 7 :(得分:1)

我将添加一个稍微修改过的版本的Anivarth(我认为它是最Python的)以供将来参考。

from math import sqrt

def divisors(n):
    divs = {1,n}
    for i in range(2,int(sqrt(n))+1):
        if n%i == 0:
            divs.update((i,n//i))
    return divs

答案 8 :(得分:1)

这是一种智能而快速的方法,可以在纯Python 3.6中为数字达到10 ** 16左右,

from itertools import compress

def primes(n):
    """ Returns  a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def factorization(n):
    """ Returns a list of the prime factorization of n """
    pf = []
    for p in primeslist:
      if p*p > n : break
      count = 0
      while not n % p:
        n //= p
        count += 1
      if count > 0: pf.append((p, count))
    if n > 1: pf.append((n, 1))
    return pf

def divisors(n):
    """ Returns an unsorted list of the divisors of n """
    divs = [1]
    for p, e in factorization(n):
        divs += [x*p**k for k in range(1,e+1) for x in divs]
    return divs

n = 600851475143
primeslist = primes(int(n**0.5)+1) 
print(divisors(n))

答案 9 :(得分:0)

这是我的解决方案。它似乎很愚蠢,但效果很好......我试图找到所有适当的除数,所以循环从i = 2开始。

g++ -std=c++11    1.cc   -o 1
1.cc: In function ‘int main(int, char**)’:
1.cc:6:47: error: use of deleted function ‘std::basic_fstream<char>::basic_fstream(const std::basic_fstream<char>&)’
     auto log = fstream{"log.txt", fstream::out};
                                               ^
In file included from 1.cc:1:0:
/usr/include/c++/4.8/fstream:776:11: note: ‘std::basic_fstream<char>::basic_fstream(const std::basic_fstream<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_fstream : public basic_iostream<_CharT, _Traits>
           ^
/usr/include/c++/4.8/fstream:776:11: error: use of deleted function ‘std::basic_iostream<char>::basic_iostream(const std::basic_iostream<char>&)’
In file included from /usr/include/c++/4.8/fstream:38:0,
                 from 1.cc:1:
/usr/include/c++/4.8/istream:795:11: note: ‘std::basic_iostream<char>::basic_iostream(const std::basic_iostream<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_iostream
           ^
/usr/include/c++/4.8/istream:795:11: error: use of deleted function ‘std::basic_istream<char>::basic_istream(const std::basic_istream<char>&)’
/usr/include/c++/4.8/istream:58:11: note: ‘std::basic_istream<char>::basic_istream(const std::basic_istream<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_istream : virtual public basic_ios<_CharT, _Traits>
           ^
/usr/include/c++/4.8/istream:58:11: error: use of deleted function ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’
In file included from /usr/include/c++/4.8/ios:44:0,
                 from /usr/include/c++/4.8/istream:38,
                 from /usr/include/c++/4.8/fstream:38,
                 from 1.cc:1:
/usr/include/c++/4.8/bits/basic_ios.h:66:11: note: ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_ios : public ios_base
           ^
In file included from /usr/include/c++/4.8/ios:42:0,
                 from /usr/include/c++/4.8/istream:38,
                 from /usr/include/c++/4.8/fstream:38,
                 from 1.cc:1:
/usr/include/c++/4.8/bits/ios_base.h:786:5: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
     ios_base(const ios_base&);
     ^
In file included from /usr/include/c++/4.8/ios:44:0,
                 from /usr/include/c++/4.8/istream:38,
                 from /usr/include/c++/4.8/fstream:38,
                 from 1.cc:1:
/usr/include/c++/4.8/bits/basic_ios.h:66:11: error: within this context
     class basic_ios : public ios_base
           ^
In file included from /usr/include/c++/4.8/fstream:38:0,
                 from 1.cc:1:
/usr/include/c++/4.8/istream:795:11: error: use of deleted function ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’
     class basic_iostream
           ^
In file included from /usr/include/c++/4.8/istream:39:0,
                 from /usr/include/c++/4.8/fstream:38,
                 from 1.cc:1:
/usr/include/c++/4.8/ostream:58:11: note: ‘std::basic_ostream<char>::basic_ostream(const std::basic_ostream<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_ostream : virtual public basic_ios<_CharT, _Traits>
           ^
/usr/include/c++/4.8/ostream:58:11: error: use of deleted function ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’
In file included from /usr/include/c++/4.8/fstream:38:0,
                 from 1.cc:1:
/usr/include/c++/4.8/istream:795:11: error: use of deleted function ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’
     class basic_iostream
           ^
In file included from 1.cc:1:0:
/usr/include/c++/4.8/fstream:776:11: error: use of deleted function ‘std::basic_ios<char>::basic_ios(const std::basic_ios<char>&)’
     class basic_fstream : public basic_iostream<_CharT, _Traits>
           ^
/usr/include/c++/4.8/fstream:776:11: error: use of deleted function ‘std::basic_filebuf<char>::basic_filebuf(const std::basic_filebuf<char>&)’
/usr/include/c++/4.8/fstream:72:11: note: ‘std::basic_filebuf<char>::basic_filebuf(const std::basic_filebuf<char>&)’ is implicitly deleted because the default definition would be ill-formed:
     class basic_filebuf : public basic_streambuf<_CharT, _Traits>
           ^
In file included from /usr/include/c++/4.8/ios:43:0,
                 from /usr/include/c++/4.8/istream:38,
                 from /usr/include/c++/4.8/fstream:38,
                 from 1.cc:1:
/usr/include/c++/4.8/streambuf:802:7: error: ‘std::basic_streambuf<_CharT, _Traits>::basic_streambuf(const std::basic_streambuf<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’ is private
       basic_streambuf(const basic_streambuf& __sb)
       ^
In file included from 1.cc:1:0:
/usr/include/c++/4.8/fstream:72:11: error: within this context
     class basic_filebuf : public basic_streambuf<_CharT, _Traits>
           ^
make: *** [1] Error 1

答案 10 :(得分:0)

如果您只关心使用列表推导而其他任何事情都不重要!

from itertools import combinations
from functools import reduce

def get_devisors(n):
    f = [f for f,e in list(factorGenerator(n)) for i in range(e)]
    fc = [x for l in range(len(f)+1) for x in combinations(f, l)]
    devisors = [1 if c==() else reduce((lambda x, y: x * y), c) for c in set(fc)]
    return sorted(devisors)

答案 11 :(得分:0)

假设factors函数返回 n 的因子(例如,factors(60)返回列表[2,2,3,5]),这里是一个用于计算 n 的除数的函数:

function divisors(n)
    divs := [1]
    for fact in factors(n)
        temp := []
        for div in divs
            if fact * div not in divs
                append fact * div to temp
        divs := divs + temp
    return divs

答案 12 :(得分:0)

如果您的PC拥有大量内存,那么使用numpy进行单行暴力就足够快了:

N = 10000000; tst = np.arange(1, N); tst[np.mod(N, tst) == 0]
Out: 
array([      1,       2,       4,       5,       8,      10,      16,
            20,      25,      32,      40,      50,      64,      80,
           100,     125,     128,     160,     200,     250,     320,
           400,     500,     625,     640,     800,    1000,    1250,
          1600,    2000,    2500,    3125,    3200,    4000,    5000,
          6250,    8000,   10000,   12500,   15625,   16000,   20000,
         25000,   31250,   40000,   50000,   62500,   78125,   80000,
        100000,  125000,  156250,  200000,  250000,  312500,  400000,
        500000,  625000, 1000000, 1250000, 2000000, 2500000, 5000000])

在慢速的PC上花费不到1秒的时间。

答案 13 :(得分:0)

我通过生成器函数的解决方案是:

def divisor(num):
    for x in range(1, num + 1):
        if num % x == 0:
            yield x
    while True:
        yield None

答案 14 :(得分:0)

尝试计算给定数字的平方根,然后循环 range(1,square_root+1)。

number = int(input("Enter a Number: "))
square_root = round(number ** (1.0 / 2))
print(square_root)
divisor_list = []
for i in range(1,square_root+1):
    if number % i == 0: # Check if mod return 0 if yes then append i and number/i in the list
        divisor_list.append(i)
        divisor_list.append(int(number/i))

print(divisor_list)

答案 15 :(得分:-1)

对我来说这很好用,也很干净(Python 3)

def divisors(number):
    n = 1
    while(n<number):
        if(number%n==0):
            print(n)
        else:
            pass
        n += 1
    print(number)

不是很快但是如你所愿一行一行地返回除数,你也可以做list.append(n)和list.append(数字),如果你真的想要

答案 16 :(得分:-1)

return [x for x in range(n+1) if n/x==int(n/x)]