上一篇博客讲到python之寻找第n个默尼森数,在课程讨论区看到一位同学的提问,觉得可以巩固一下知识,将问题和讲解总结在这里。
问题点这里
(课程关闭后可能打不开)
该同学的代码
def prime(num):
for i in range(2,num//2):
if (num % i)==0:
return False
else:
return True
def monisen(no):
b=[2]
i=2
while len(b) < no:
if prime(i) and prime(2**i-1):
b.append(2**i-1)
i +=1
else:
i+=1
print(b[-1])
print(monisen(int(input())))
标准输入为4的时候,执行后的结果是这样的
31
None
首先,第一个问题看输出很明显也很容易改,因为输出有两个而要求只是一个,再仔细看下代码发现第二个函数monisen里已经出现了print函数,这时候再对函数进行print当然是没有输出显示None了。只要将print改成return即可。
然后一个问题稍微复杂一点,回想一下默尼森数应该是[3,7,31,127…]这样的一组数,所以当输入为4的时候输出应该是127。而此时输出为31,显然不对。再看代码,发现默尼森数的列表b中最先加进了2这个数,这时候发现问题,加进去的应该是3而不是2,同时开始的i应该置为3(第二个素数)而不是2。
def prime(num):
for i in range(2,num//2):
if (num % i)==0:
return False
else:
return True
def monisen(no):
b=[3]
i=3
while len(b) < no:
if prime(i) and prime(2**i-1):
b.append(2**i-1)
i +=1
else:
i+=1
return b[-1]
print(monisen(int(input())))
上面3的代码已经可以通过一般的测试了,也确实通过了MOOC的测试用例的考察。是对该同学代码改动最少的版本。但是其实这段代码还是有问题的,列举如下。
先解决第二个问题,经过查询发现真的是有for else语句的,但是要注意有一个坑,就是当for全部迭代完的时候,无论if语句里面是不是真,else都会执行,所以在一般的使用中需要在if语句中加break语句使之跳出可以避免执行else语句。
详细参考Python中for循环搭配else的陷阱
(在本例中因为return就直接跳出了所以不会出现问题。)
第一个问题就靠分类讨论,将其分离出来单独处理。
import math
def prime(num):
for i in range(2,int(math.sqrt(num))+1):
if (num % i)==0:
return False
return True
def monisen(no):
b=[3,7]
i=5
while len(b) < no:
if prime(i) and prime(2**i-1):
b.append(2**i-1)
i +=1
else:
i+=1
return b[-1]
print(monisen(int(input())))
顺便把上界也改小了。