我用Python编写代码来计算10000以下友好数字的总和:
def amicable(a, b):
total = 0
result = 0
for i in range(1, a):
if a % i == 0:
total += i
for j in range(1, b):
if b % j == 0:
result += j
if total == b and result == a:
return True
return False
sum_of_amicables = 0
for m in range (1, 10001):
for n in range (1, 10001):
if amicable(m, n) == True and m != n:
sum_of_amicables = sum_of_amicables + m + n
Python 2.7.11中的代码运行时间超过20分钟。好吗?我该如何改进呢?
答案 0 :(得分:3)
优化为O(n)
def sum_factors(n):
result = []
for i in xrange(1, int(n**0.5) + 1):
if n % i == 0:
result.extend([i, n//i])
return sum(set(result)-set([n]))
def amicable_pair(number):
result = []
for x in xrange(1,number+1):
y = sum_factors(x)
if sum_factors(y) == x and x != y:
result.append(tuple(sorted((x,y))))
return set(result)
运行它
start = time.time()
print (amicable_pair(10000))
print time.time()-start
结果
set([(2620, 2924), (220, 284), (6232, 6368), (1184, 1210), (5020, 5564)])
0.180204153061
在macbook pro上只需0.2秒
答案 1 :(得分:2)
让我们分解代码并改进花费大量时间的代码部分。
<强> 1 - 强>
如果您将if amicable(m, n) == True and m != n:
替换为if m != n and amicable(m, n) == True:
,它将为您保存10000次调用amicable方法(最昂贵的方法)m != n
为false
。
2 - 在amicable
方法中,您将循环1到n以查找这两个数字的所有因子。您需要一个更好的算法来查找因子。您可以使用提到的here。为了找到因素,它会将O(n)
复杂度降低到O(sqrt(n))
。
def factors(n):
return set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
考虑到代码上方的两点都是
def amicable(a, b):
if sum(factors(a) - {a}) == b and sum(factors(b) - {b}) == a:
return True
return False
sum_of_amicables = 0
for m in range (1, 10001):
for n in range (1, 10001):
if m!= n and amicable(m, n) == True:
sum_of_amicables = sum_of_amicables + m + n
这个最终代码花了 10分钟为我跑,这是你提到的时间的一半。
我可以通过优化factors
方法将其优化为 1:30分钟。
对factors
方法有10000 * 10000次调用。并且每个号码都会调用factors
10000次。也就是说,它为相同的数字计算因子10000次。因此,我们可以通过缓存先前因子计算的结果来优化它,而不是在每次调用时计算它们。
以下是我修改factors
以缓存结果的方法。
def factors(n, cache={}):
if cache.get(n) is not None:
return cache[n]
cache[n] = set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
return cache[n]
完整代码:(运行时间1:30分钟)
所以完整和最终的代码变成了
def factors(n, cache={}):
if cache.get(n) is not None:
return cache[n]
cache[n] = set(reduce(list.__add__,
([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
return cache[n]
def amicable(a, b):
if sum(factors(a) - {a}) == b and sum(factors(b) - {b}) == a:
return True
return False
sum_of_amicables = 0
for m in range (1, 10001):
for n in range (1, 10001):
if m!= n and amicable(m, n) == True:
sum_of_amicables = sum_of_amicables + m + n
您仍然可以进一步改进它。
提示: sum
每个号码也会被调用10000次。
答案 2 :(得分:0)
请注意,您不需要进行双循环。只需将M从1循环到10000, 对每个M进行分解并计算除数之和:S(M)。然后检查N = S(M)-M是否具有相同的除数之和。这是一个源自友好对的定义的直接算法。
优化友好对搜索还有很多其他技巧。只需几分之一秒即可找到1,000,000,000以下的所有友好数字。阅读this in-depth article,您还可以查看该文章中的参考C++ code。
答案 3 :(得分:0)
添加答案:
def sum_factors(self, n):
s = 1
for i in range(2, int(math.sqrt(n))+1):
if n % i == 0:
s += i
s += n/i
return s
def amicable_pair(self, number):
result = 0
for x in range(1,number+1):
y = self.sum_factors(x)
if self.sum_factors(y) == x and x != y:
result += x
return result
不需要集合或数组。提高存储和清晰度。
答案 4 :(得分:0)
#fetching two numbers from the user
num1=int(input("Enter first number"));
num2=int(input("enter the second number"));
fact1=[];
fact2=[];
factsum1=0;
factsum2=0;
#finding the factors of the both numbers
for i in range(1,num1):
if(num1%i==0):
fact1.append(i)
for j in range(1,num2):
if(num2%j==0):
fact2.append(j)
print ("factors of {} is {}".format(num1,fact1));
print ("factors of {} is {}".format(num2,fact2));
#add the elements in the list
for k in range(len(fact1)):
factsum1=factsum1+fact1[k]
for l in range(len(fact2)):
factsum2=factsum2+fact2[l]
print (factsum1);
print (factsum2);
#compare them
if(factsum1==num2 and factsum2==num1 ):
print "both are amicable";
else:
print "not amicable ";
this is my owm understanding of the concept
答案 5 :(得分:0)
大家仔细阅读代码和注释,可以轻松理解
def amicable_number(number):
list_of_tuples=[]
amicable_pair=[]
for i in range(2,number+1): # in which range you want to find amicable
divisors = 1 # initialize the divisor
sum_of_divisors=0 #here we add the divisors
while divisors < i: # here we take one number and add their divisors
if i%divisors ==0: #checking condition of complete divison
sum_of_divisors += divisors
divisors += 1
list_of_tuples.append((i,sum_of_divisors)) #append that value and sum of there divisors
for i in list_of_tuples:
#with the help of these loops we find amicable with duplicacy
for j in list_of_tuples:
if i[0] == j[1] and i[1] == j[0] and j[0] != j[1]: #condition of amicable number
amicable_pair.append((j[0],i[0])) # append the amicable pair
# i write this for_loop for removing the duplicacy if i will mot use this for loop this
# be print both (x,y) and (y,x) but we need only one among them
for i in amicable_pair:
for j in amicable_pair[1:len(amicable_pair)]: #subscript the list
if i[0] == j[1]:
amicable_pair.remove(i) # remove the duplicacy
print('list of amicable pairs number are: \n',amicable_pair)
amicable_number(284) #call the function