python全数字问题_关于python:获取一个数字的所有除数的最佳方法是什么?

这是非常愚蠢的方式:

1

2

3

4def 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

2for i in factorGenerator(100):

print i

是:

1

2(2, 2)

(5, 2)

我不知道这对我想做的事情有多有用(我为其他问题编码了它),不管怎样,我想要一个更聪明的方法

1

2for i in divisorGen(100):

print i

输出此:

1

2

3

4

5

6

7

8

91

2

4

5

10

20

25

50

100

更新:非常感谢Greg Hewgill和他的"聪明的方式":)计算100000000的除数时,他用0.01秒的速度计算了我机器上的39秒,非常酷:d

更新2:不要说这是这篇文章的副本。计算一个给定数的除数不需要计算所有的除数。这是一个不同的问题,如果你认为不是,那么在维基百科上寻找"除数函数"。在发帖前阅读问题和答案,如果你不理解主题是什么,不要添加不有用的和已经给出的答案。

之所以有人认为这个问题几乎是"计算给定数字除数的算法"的一个副本,是因为在这个问题中,建议的第一步是找到所有的除数,我相信这正是你想做的?

安德鲁为了找到有多少个除数,你只需要找到素数,然后用它们来计算可能有多少个除数。在这种情况下不需要求除数。

@Andrea Ambu,请更正您的函数名

考虑到factorgenerator函数,这里有一个除数器应该工作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15def 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

该算法的整体效率完全取决于因子发生器的效率。

哇,用0.01来计算所有的除数100000000,而用了39个愚蠢的方式(停在n/2),非常酷,谢谢!

对于我们这些不懂Python的人来说,这到底在做什么?

一氧化碳:计算给定因子的所有乘法组合。其中大部分应该是不言自明的,"收益"线就像一个收益,但在返回一个值之后会继续。[0]*NFactors创建长度为零的NFactors列表。reduce(…)计算因子的乘积。

reduce和lambda符号实际上让我困惑。我尝试在C语言中实现一种算法,使用递归函数遍历因子数组并将它们相乘,但对于具有许多因子的1024这样的数字,它的性能似乎很糟糕。

为什么不使用operator.mul?

@Speckiniusflecksis:没有理由,operator.mul在那里也同样有效。

当然,这比将每个数除以n/2甚至sqrt(n)要好得多,但是这种特殊的实现有两个缺点:非常内敛:成吨的乘法和求幂运算,重复地乘以相同的幂次等等。这看起来像Python,但我不认为Python是在扼杀性能。问题二:除数没有按顺序返回。

谢谢格雷格。您的算法激发了我在这里更实用的版本:rosettacode.org/wiki/proper_divisions python:_prime_fact&zwnj;&8203;ors

代码产生错误,TypeError: 'int' object has no attribute '__getitem__',向下投票

@Greghewgill是的,我也会得到一个_TypeError: 'int' object has no attribute '__getitem__'错误。它是可解的吗?

未解析的引用"reduce"。我应该进口什么?功能工具?

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

如前所述,这是一个NP或"困难"问题。详尽的搜索,你做它的方式,差不多是它得到的保证的答案。加密算法等使用这个事实来帮助保护它们。如果有人要解决这个问题,大多数(如果不是全部)我们当前的"安全"通信都会变得不安全。

python代码:

1

2

3

4

5

6

7

8

9

10

11

12

13import 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]

因为,一旦你有了1到10之间的元素列表,你就可以生成11到100之间的任何元素。你得到1,2,4,5,10。将100除以这些元素中的每一个,就可以得到100、50、20、25、10。

根据定义,因子总是成对生成的。通过只搜索sqrt(n),你的工作被一个2次方切断了。

它比我文章中的版本快得多,但比使用基本因子的版本慢得多

我同意这不是最好的解决办法。我只是简单地指出了一种"更好"的搜索方式,这种方式可以节省很多时间。

因子分解并不是NP硬的。en.wikipedia.org/wiki/integer_factorization的问题是找到所有除数,因为已经找到了基本因子(硬因子)。

这意味着因子分解是一种扩展的NP硬算法。事实上,他们已经有了主要因素,这一点无关紧要。给出的例子是详尽的搜索,这是缓慢和困难的。

如果我不是N/I:应该是如果我!=n/i:,对于平方根大于256'is'的值将不起作用。

对于小数字,它比使用质数因子的版本快得多。

很好的回答

我想你可以停在江户一号〔4〕而不是2号。

我给你举个例子,这样你就容易理解了。现在,sqrt(28)是5.29,所以ceil(5.29)将是6。所以如果我在6点停下来,我就能得到所有的除数。怎么用?

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

1

2

3

4

5

6

7

8import 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开始。

jsBas.jpg

所以在所有迭代的末尾,当我把商和除数添加到我的列表中时,28的所有除数都被填充了。

来源:如何确定一个数的除数

很好,很好!!math.sqrt(n) instead of n/2是优雅的必备品

这是不正确的。你忘了n是可以被它自己整除的。

回答得很好。简单明了。但对于python 3,有两个必要的更改:n/i应该使用int(n/i)键入,因为n/i产生浮点数。另外,在python 3中,rangex已被弃用,并已被range替换。

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

这个是:

可读性

短的

独立、复制和粘贴就绪

快速(在有很多素数因子和除数的情况下,比公认的解快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

32def 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

我会用while i <= limit代替while i*i <= nn,其中limit = math.sqrt(n)

我喜欢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

69from 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发帖。我期待任何反馈。

在python 2.6中有一个itertools.product()。

使用生成器而不是list.append everywhere的版本可能更干净。

埃拉托森筛可用于生成小于或等于sqrt(n)stackoverflow.com/questions/188425/project euler problem 193&zwnj;&8203;605的素数。

编码样式:指数=[k**x代表k,v代表factors.items()代表x代表范围(v+1)]

对于ListExponents:【k**x表示范围内的x(v+1)】表示k,v表示factors.items()]

改编自codereview,这里有一个与num=1一起工作的变体!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17from 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))

我好像犯了一个错误:NameError: global name 'prime_factors' is not defined。其他答案和最初的问题都不能定义这是什么。

我只想添加一个稍微修改过的版本的anivarth(我相信这是最Python)供将来参考。

1

2

3

4

5

6

7

8from 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

33from 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))

用来寻找素数和进行因式分解的算法的名称是什么?因为我想在C中实现这个。

老问题,但我的看法是:

1

2

3

4def 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

3def divisorGenerator(n):

for x in reversed(divs(n, n)):

yield x

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

如果你只关心使用列表理解,而对你来说没有其他重要的东西!

1

2

3

4

5

6

7

8from 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

11import 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

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

1

2

3

4

5

6

7

8

9function 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吗?无论如何,它肯定不是python 3.x。

它是伪代码,应该很容易翻译成python。

迟了3年,总比不迟好:)我认为这是最简单、最短的代码。我没有一个比较表,但是我可以在i5笔记本电脑上分解和计算一百万分之一秒的除数。

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

1

2

3

4

5

6

7

8

9def divisors(number):

n = 1

while(n

if(number%n==0):

print(n)

else:

pass

n += 1

print(number)

不是很快,但可以按需要逐行返回除数,也可以执行list.append(n)和list.append(number)操作

你读过手术室提议的非常愚蠢的方式吗?

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

提问者要求更好的算法,而不仅仅是更漂亮的格式。

您需要使用范围(1,n+1)来避免被零除。另外,如果使用python 2.7,那么第一个除法需要使用float(n),这里1/2=0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值