Python识别完美数

640?wx_fmt=jpeg


作者 | zglg 

来源 | Python与算法社区(ID:alg-channel)

 

01 完美数


完美数(perfect number,又称完全数)指,它所有的真因子(即除了自身以外的因子)和,恰好等于它自身。


第一个完美数:6,

第二个完美数:28,

第三个完美数:496,

第四个完美数:8128,

第五个完美数:33550336,

.......


02 探索


在茫茫数海中,第五个完美数(33550336)要大得多,居然藏在千万位数的深处!它在十五世纪被人们发现,计算机问世后,借助这一有力工具,数论爱好者们继续探索。


笛卡尔曾公开预言:“找出的完美数是不会多的,好比人类一样,要找一个完美人亦非易事


时至今日,人们一直没有发现有奇完美数的存在。于是是否存在奇完美数成为数论中的一大难题。只知道即便有,这个数也是非常之大,并且需要满足一系列苛刻的条件。


经过不少数学家研究,到2013年为止,一共找到了48个完美数。


0 3 有趣性质


1. 目前发现的完美数都是以6或8结尾,会不会有奇完全数存在?如果存在,它必须大于10^300,至今无人能回答这些问题。


2. 所有的完美数都是三角形数。例如:

6=1+2+3

28=1+2+3+...+6+7

8128=1+2+3…+126+127


3. 所有完美数的倒数都是调和数。例如:

1/1+1/2+1/3+1/6=2

1/1+1/2+1/4+1/7+1/14+1/28=2

1/1+1/2+1/4+1/8+1/16+1/31+1/62+1/124+1/248+1/496=2


4. 可以表示成连续奇立方数之和。除6以外的完全数,都可以表示成连续奇立方数之和,并规律式增加。例如:

28=1³+3^3

496=1^3+3^3+5^3+7^3

8128=1^3+3^3+5^3+……+15^3

33550336=1^3+3^3+5^3+……+125^3+127^3


  04 判断


如何判断是为否完美数呢?在计算机数值型可以表达的的范围内,我们可以尝试找一找。


这是一道leetcode题(No.507),我前段时间写过一个解,在leetcode平台上已通过:


1class Solution:
2    def checkPerfectNumber(self, num: int) -> bool:
3        sum = 1
4        tmp = num
5        if num == 0 or num==1:
6            return False
7        while num%2 == 0:
8            num /= 2
9            sum += num+tmp/num
10        return sum==tmp


已知完美数都以6或8结尾,所以才有了上面的方法,注意这不是寻找一个数所有因子的方法。使用6或8结尾这个小trick,实现更高效( > 95.26%),但不严谨。


640?wx_fmt=png


很遗憾,今天我发现这是一个错误的解法,虽然在Leetcode上已经通过。原因如下,我们试图打印尽可能多的完美数:


1import sys
2if __name__ == "__main__":
3    s = Solution()
4    i,j = 0,0
5    while(i<sys.maxsize):
6        isPerfect = s.checkPerfectNumber(i)
7        if isPerfect is True:
8            j+=1
9            print("第%d个完美数: %d"%(j,i))
10        i+=1


第1个完美数: 6

第2个完美数: 28

第3个完美数: 120

第4个完美数: 496

第5个完美数: 2016

第6个完美数: 8128

第7个完美数: 32640

第8个完美数: 130816

第9个完美数: 523776

第10个完美数: 2096128


很明显,120不是一个完美数,因此,可以确定Leetcode平台遗漏了这些cases,已经将此问题提交到Leetocode,如下所示:


640?wx_fmt=png


05 正解


如果遍历所有的小于num的数,check是否为其因子,时间复杂度为o(n),在平台上提交会超时。


一种更好的解法,时间复杂度为O(sqrt(n)), 因为num的两个因子:num_i和num_j,假设num_i < num_j ,则 num_i 的最大值为 sqrt(num), 所以我们只需要遍历到sqrt(num)即可。


代码如下:


 1class Solution: 2    def checkPerfectNumber(self, num: int) -> bool: 3        if num <= 0: 4            return False 5 6        i, sum = 1, 0 7        while i*i <= num: 8            if num % i == 0: 9                sum += i10            if i*i != num:11                sum += num / i12            i += 11314        return sum - num == num class Solution:
2    def checkPerfectNumber(self, num: int) -> bool:
3        if num <= 0:
4            return False
5
6        i, sum = 10
7        while i*i <= num:
8            if num % i == 0:
9                sum += i
10            if i*i != num:
11                sum += num / i
12            i += 1
13
14        return sum - num == num 


06 更多完美数


6. 8,589,869,056

7. 137,438,691,328

8. 2,305,843,008,139,952,128

9. 2,658,455,991,569,831,744,654,692,615,953,842,176

10.191,561,942,608,236,107,294,793,378,084,303,638,130,997,321,548,169,216

11.13,164,036,458,569,648,337,239,753,460,458,722,910,223,472,318,386,943,117,783,728,128

12.14,474,011,154,664,524,427,946,373,126,085,988,481,573,677,491,474,835,889,066,354,349,131,199,152,128

……

……

47 ……2^42643800 X (2^42643801-1)

48 ……2^57885160 X (2^57885161-1)

由于后面数字位数较多,例子只列到12个,第13个有314位。

到第39个完全数有25674127位数,据估计它以四号字打出时需要一本字典大小的书。


(*本文仅代表作者观点,转载请联系原作者)


程序员大本营


基于过去得出的总结,我们才能看得懂看得到未来。关注“优快云技术开发社区”公众号,回复:程序员大本营,免费获取《程序员大本营》6月刊。


640?wx_fmt=jpeg

推荐阅读:


640?wx_fmt=png你点的每个“在看”,我都认真当成了喜欢
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值