[python] 숫자의 모든 제수를 구하는 가장 좋은 방법은 무엇입니까?
다음은 매우 멍청한 방법입니다.
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)
등 …
즉, 출력
for i in factorGenerator(100):
print i
is :
(2, 2)
(5, 2)
내가 원하는 일에 얼마나 유용한 지 모르겠습니다 (다른 문제에 대해 코딩했습니다) 어쨌든 더 똑똑한 방법을 원합니다.
for i in divisorGen(100):
print i
이것을 출력하십시오 :
1
2
4
5
10
20
25
50
100
업데이트 : Greg Hewgill과 그의 “스마트 한 방법”에게 많은 감사를드립니다 . 🙂 100000000의 모든 제수를 계산하는 데 0.01 초가 걸렸습니다.
업데이트 2 : 이 게시물 의 중복이라고 말하지 마세요. 주어진 숫자의 제수를 계산할 때 모든 제수를 계산할 필요는 없습니다. 다른 문제입니다. 그렇지 않다고 생각한다면 위키피디아에서 “제수 함수”를 찾으십시오. 게시하기 전에 질문과 답변을 읽으십시오. 주제가 무엇인지 이해하지 못하는 경우 유용하지 않고 이미 제공된 답변을 추가하지 마십시오.
답변
귀하의 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
.
답변
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]
답변
이것에 대한 많은 해결책이 이미 있지만 정말 이것을 게시해야합니다 🙂
이것은 :
- 읽을 수있는
- 짧은
- 자체 포함, 복사 및 붙여 넣기 준비
- 빠름 (소인수와 제수가 많은 경우 허용 된 솔루션보다 10 배 이상 빠름)
- python3, python2 및 pypy 호환
암호:
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
답변
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
그래서
따라서 모든 반복이 끝날 때 몫과 제수를 목록에 추가하면 28의 모든 제수가 채워집니다.
출처 : 숫자의 제수를 결정하는 방법
답변
나는 Greg 솔루션을 좋아하지만 파이썬처럼 더 좋았 으면 좋겠다. 더 빠르고 가독성이 좋을 것 같습니다. 그래서 얼마간의 코딩 후에 나는 이것을 나왔습니다.
처음 두 함수는 목록의 데카르트 곱을 만드는 데 필요합니다. 그리고이 문제가 발생할 때마다 재사용 할 수 있습니다. 그건 그렇고,이 문제에 대한 표준 솔루션을 아는 사람이 있으면 저에게 연락 주시기 바랍니다.
“Factorgenerator”는 이제 사전을 반환합니다. 그런 다음 사전은 “제수”에 입력되어 먼저 목록 목록을 생성하는 데 사용합니다. 여기서 각 목록은 p 소수를 갖는 p ^ n 형식의 인수 목록입니다. 그런 다음 해당 목록의 데카르트 곱을 만들고 마지막으로 Greg의 솔루션을 사용하여 제수를 생성합니다. 우리는 그들을 분류하고 반환합니다.
나는 그것을 테스트했으며 이전 버전보다 조금 더 빠른 것 같습니다. 더 큰 프로그램의 일부로 테스트했기 때문에 얼마나 더 빠른지 말할 수는 없습니다.
Pietro Speroni (pietrosperoni dot it)
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에 게시하는 것은 처음입니다. 피드백을 기다리고 있습니다.
답변
다음은 순수 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))
답변
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))