What is the best way to get all the divisors of a number?
这是非常愚蠢的方式:
1 2 3 4 | def divisorGenerator(n): for i in xrange(1,n/2+1): if n%i == 0: yield i yield n |
我想得到的结果和这个相似,但我想要一个更聪明的算法(这个算法太慢太笨了:-)
我可以很快找到基本因子及其多重性。我有一个发生器,它以这种方式产生因子:
(系数1,乘数1)(系数2,倍数2)(系数3,倍数3)等等……
即输出
1 2 | for i in factorGenerator(100): print i |
号
是:
1 2 | (2, 2) (5, 2) |
我不知道这对我想做的事情有多有用(我为其他问题编码了它),不管怎样,我想要一个更聪明的方法
1 2 | for i in divisorGen(100): print i |
。
输出此:
1 2 3 4 5 6 7 8 9 | 1 2 4 5 10 20 25 50 100 |
更新:非常感谢Greg Hewgill和他的"聪明的方式":)计算100000000的除数时,他用0.01秒的速度计算了我机器上的39秒,非常酷:d
更新2:不要说这是这篇文章的副本。计算一个给定数的除数不需要计算所有的除数。这是一个不同的问题,如果你认为不是,那么在维基百科上寻找"除数函数"。在发帖前阅读问题和答案,如果你不理解主题是什么,不要添加不有用的和已经给出的答案。
考虑到factorgenerator函数,这里有一个除数器应该工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
该算法的整体效率完全取决于因子发生器的效率。
为了扩展Shimi所说的内容,您应该只运行从1到n的平方根的循环,然后找到这对,执行
如前所述,这是一个NP或"困难"问题。详尽的搜索,你做它的方式,差不多是它得到的保证的答案。加密算法等使用这个事实来帮助保护它们。如果有人要解决这个问题,大多数(如果不是全部)我们当前的"安全"通信都会变得不安全。
python代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 | [1, 2, 4, 5, 10, 20, 25, 50, 100] |
号
我想你可以停在江户一号〔4〕而不是2号。
我给你举个例子,这样你就容易理解了。现在,
首先看到代码,然后看到图像:
1 2 3 4 5 6 7 8 | 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)) |
号
现在,请参见下图:
假设我已经将
。
所以在所有迭代的末尾,当我把商和除数添加到我的列表中时,28的所有除数都被填充了。
来源:如何确定一个数的除数
虽然已经有很多解决方案,但我真的要发布这个:)
这个是:
- 可读性
- 短的
- 独立、复制和粘贴就绪
- 快速(在有很多素数因子和除数的情况下,比公认的解快10倍以上)
- python3、python2和pypy兼容
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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 |
号
我喜欢Greg解决方案,但我希望它更像Python。我觉得它会更快更易读;经过一段时间的编码之后,我发现了这个。
前两个函数用于生成列表的笛卡尔积。并且可以在不出现此问题的情况下重复使用。顺便说一下,我必须自己编写这个程序,如果有人知道这个问题的标准解决方案,请随时与我联系。
"factorgenerator"现在返回字典。然后字典被输入"除数",除数首先用来生成一个列表列表,其中每个列表都是p^n和p prime形式的因子列表。然后我们得到这些列表的笛卡尔积,最后用格雷格解生成除数。我们把它们分类,然后把它们退回。
我测试过它,它似乎比以前的版本快一点。我把它作为一个更大程序的一部分进行了测试,所以我不能说它到底快了多少。
Pietro Speroni(Pietrosperoni点状)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 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) |
。
附笔。这是我第一次向StackOverflow发帖。我期待任何反馈。
改编自codereview,这里有一个与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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)) |
我只想添加一个稍微修改过的版本的anivarth(我相信这是最Python)供将来参考。
1 2 3 4 5 6 7 8 | 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 |
在纯Python3.6中,对于10*16及以下的数字,这是一种智能且快速的方法,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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)) |
号
老问题,但我的看法是:
1 2 3 4 | def divs(n, m): if m == 1: return [1] if n % m == 0: return [m] + divs(n, m - 1) return divs(n, m - 1) |
您可以代理:
1 2 3 | def divisorGenerator(n): for x in reversed(divs(n, n)): yield x |
。
注意:对于支持的语言,这可能是尾部递归。
如果你只关心使用列表理解,而对你来说没有其他重要的东西!
1 2 3 4 5 6 7 8 | 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) |
号
这是我的解决方案。它看起来很蠢,但效果很好……我试图找到所有合适的除数,所以循环从i=2开始。
1 2 3 4 5 6 7 8 9 10 11 | import math as m def findfac(n): faclist = [1] for i in range(2, int(m.sqrt(n) + 2)): if n%i == 0: if i not in faclist: faclist.append(i) if n/i not in faclist: faclist.append(n/i) return facts |
。
假设
1 2 3 4 5 6 7 8 9 | 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 |
。
对我来说,这很好,也很干净(python 3)
1 2 3 4 5 6 7 8 9 | 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(number)操作
1 | return [x for x in range(n+1) if n/x==int(n/x)] |
。