我正在研究Project Euler问题,该问题需要对整数进行分解。我可以得出所有素数的列表,这些素数是给定数字的因子。算术的基本定理意味着我可以使用此列表来推导数字的每个因子。
我目前的计划是将每个数字放在基本素数列表中并提高其功效,直到它不再是整数因子来找到每个素数的最大指数。然后,我将乘以素数指数对的每个可能组合。
例如,对于180:
Given: prime factors of 180: [2, 3, 5]
Find maximum exponent of each factor:
180 / 2^1 = 90
180 / 2^2 = 45
180 / 2^3 = 22.5 - not an integer, so 2 is the maximum exponent of 2.
180 / 3^1 = 60
180 / 3^2 = 20
180 / 3^3 = 6.6 - not an integer, so 2 is the maximum exponent of 3.
180 / 5^1 = 36
180 / 5^2 = 7.2 - not an integer, so 1 is the maximum exponent of 5.
接下来,将这些组合的每个组合达到最大指数以获得因子:
2^0 * 3^0 * 5^0 = 1
2^1 * 3^0 * 5^0 = 2
2^2 * 3^0 * 5^0 = 4
2^0 * 3^1 * 5^0 = 3
2^1 * 3^1 * 5^0 = 6
2^2 * 3^1 * 5^0 = 12
2^0 * 3^2 * 5^0 = 9
2^1 * 3^2 * 5^0 = 18
2^2 * 3^2 * 5^0 = 36
2^0 * 3^0 * 5^1 = 5
2^1 * 3^0 * 5^1 = 10
2^2 * 3^0 * 5^1 = 20
2^0 * 3^1 * 5^1 = 15
2^1 * 3^1 * 5^1 = 30
2^2 * 3^1 * 5^1 = 60
2^0 * 3^2 * 5^1 = 45
2^1 * 3^2 * 5^1 = 90
2^2 * 3^2 * 5^1 = 180
所以因素列表= [1,2,3,4,5,6,9,10,12,15,18,20,30,36,45,60,90,180]
这是我到目前为止的代码。两个问题:首先,我认为它根本不是Pythonic。我想解决这个问题。其次,我真的没有Pythonic方法来进行组合的第二步。出于耻辱,我让你免于那些荒谬的循环。
n是我们要考虑的数字。 listOfAllPrimes是一个预先计算的高达1000万的素数列表。
def getListOfFactors(n, listOfAllPrimes):
maxFactor = int(math.sqrt(n)) + 1
eligiblePrimes = filter(lambda x: x <= maxFactor, listOfAllPrimes)
listOfBasePrimes = filter(lambda x: n % x ==0, eligiblePrimes)
listOfExponents = [] #(do I have to do this?)
for x in listOfBasePrimes:
y = 1
while (x**(y+1)) % n == 0:
y += 1
listOfExponents.append(y)
答案 0 :(得分:10)
而不是指数列表,只需重复每个素数因子 因子的次数。之后,处理生成的primefactors
重复列表,itertools.combinations可以满足您的需求 - 您只需要包含长度为2到len(primefactors) - 1
项的组合(只有一个的组合是主要因素,它们都是原始数字 - 如果你也想要那些,只需使用range(1, len(primefactors) + 1)
而不是我的主要建议会使用的range(2, len(primefactors))
。
结果会有重复(例如,6
会出现两倍作为12
因子,因为后者的primefactors
将是[2, 2, 3]
)他们可以当然要以通常的方式排除(例如sorted(set(results))
)。
要计算给定primefactors
的{{1}},请考虑例如:
listOfAllPrimes
答案 1 :(得分:5)
为什么从一系列素数因子开始你的解决方案?当你对一个数字进行分解时,你可以很容易地得到所有的素数因子(重复),并从中得到每个因子的指数。考虑到这一点,你可以这样写:
import itertools
prime_factors = get_prime_factors(180)
# 2, 2, 3, 3, 5
factorization = [(f, len(list(fs))) for (f, fs) in itertools.groupby(prime_factors)]
# [(2, 2), (3, 2), (5, 1)]
values = [[(factor**e) for e in range(exp+1)] for (factor, exp) in factorization]
# [[1, 2, 4], [1, 3, 9], [1, 5]]
print sorted(product(xs) for xs in itertools.product(*values))
# [1, 2, 3, 4, 5, 6, 9, 10, 12, 15, 18, 20, 30, 36, 45, 60, 90, 180]
这里没有实现 get_prime_factors
和product
,但是你明白了(两者都很简单)
恕我直言,作为数学问题,欧拉问题可以通过功能而不是命令式风格很好地解决(尽管我承认某些解决方案可能不会像所希望的那样以pythonic形式出现)。
答案 2 :(得分:2)
在获得重复素数列表后,您可以使用itertools.combinations()
获取所有可能的因素组合,例如[2, 2, 3, 3, 5]
180
。然后,简单地将每个组合中的组件相乘会得到一个因素。
答案 3 :(得分:2)
有一些更酷的Python功能:
def factors( num ):
for p in primes:
if num==1: break # stop when num is 1
while True: # these factors may be repeated
new, rest = divmod(num, p) # does div and mod at once
if rest==0: # its divisible
yield p # current prime is factor
num = new # continue with the div'd number
else:
break # no factor so break from the while
print list(factors(2*2*3*3*5*7*11*11*13)) # [2, 2, 3, 3, 5, 7, 11, 11, 13] ofc
答案 4 :(得分:1)
这是解决原始问题的简单而有效的解决方案:
def getDivisors(n):
divisors = []
d = 1
while d*d < n:
if n % d == 0:
divisors.append(d)
divisors.append(n / d);
d += 1
if d*d == n:
divisors.append(d)
return divisors
输出列表未排序。如果你愿意,你可以把它变得更“pythonic”,无论那意味着什么。
答案 5 :(得分:1)
一体化解决方案;即不需要现有的主要因素列表。
#!/usr/bin/python3 -O
from primegen import erat3 as generate_primes # see Note[1]
import operator as op, functools as ft, itertools as it
def all_factors(number):
prime_powers= []
for prime in generate_primes(): # for prime in listOfAllPrimes
if prime > number: break
this_prime_powers= [1]
new_number, modulo= divmod(number, prime)
while not modulo:
number= new_number
this_prime_powers.append(this_prime_powers[-1] * prime)
new_number, modulo= divmod(number, prime)
if len(this_prime_powers) > 1:
prime_powers.append(this_prime_powers)
# at this point:
# if number was 360, prime_powers is [[1, 2, 4, 8], [1, 3, 9], [1, 5]]
# if number was 210, prime_powers is [[1, 2], [1, 3], [1, 5], [1, 7]]
return sorted(
ft.reduce(op.mul, combination, 1)
for combination in it.product(*prime_powers))
if __name__ == "__main__":
def num_result(number):
return number, all_factors(number)
print(num_result(360))
print(num_result(210))
print(num_result(7))
注意[1] :作为素数生成器,您可以从How to implement an efficient infinite generator of prime numbers in Python?中选择一个或使用您自己的(listOfAllPrimes
)。
这会产生一个完整的因子列表,即包括1
和number
参数本身。如果您想省略这些,可以使用all_factors(number)[1:-1]
。
$ allfactors.py
(360, [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, 24, 30, 36, 40, 45, 60, 72, 90, 120, 180, 360])
(210, [1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210])
(7, [1, 7])