如何用算法优雅地相亲

前天在朋友陈哥微信群里看到这么个征友信息:
在这里插入图片描述
陈哥也是第一时间破解了其中奥秘,加到了对方好友并奉上了答案:
在这里插入图片描述
至于之后剧情的发展就不得而知了~

自己动手,丰衣足食;Python在手,妹子我有!让我们以入门级的Python编码,外加高中数学级别的算法来破解这个相亲算法题:

  1. 微信ID是NY后面跟两个质数,大的在前小的在后,二数乘积为707829217
  2. 附加题目是微信ID数字基础上,从1开始到该数字的奇数序列中,一共出现了多少次3

初步思路

先看第一个,既然两个质数(质数定义)乘积固定,那么707829217除了这两个数外也就不存在其他质因数。数量级较小,我们直接采用穷举法,从1开始列举每一个1-707829217范围内数字,并将707829217与其进行除法运算,所得余数为0的第一个数就是我们要求的较小的质数,即可停止运算过程,707829217除以该小质数获取大质数,将两个质数拼接,目标1达成。

接下来看第二个,注意这里的出现多少次3这一规则,数字33是出现了两次3,数字3313是出现了三次3的。最基础的思路还是穷举,将1到ID数字全部列出,计算3出现的所有次数。当然因为数量级太大,后续可以优化算法。

Python编码

  • 求乘积为707829217的大小质数:

按照思路,我们穷举1到乘积的所有数字进行求余运算,因为只考虑质数,这里我把范围设成了range(3,707829217),只要乘积num和被穷举的i相除余数为0时,i即所求的小质数,再用num除以i获取大质数,运算结束。

在这里插入图片描述
根据运算结果,将大质数86627和8171拼接成结果866278171。

  • 求1到866278171所有奇数中出现3的次数:

首先仍是穷举思路,用for循环列出1到866278171所有奇数。因为字符串有个str.count()函数可以计算字符串中某个字符出现次数,所以我们将所有数字先转化为字符串,再用str.count(“3”)来获取其中出现3的次数。但是可以预见,数量级不小,运行时间应该挺长,我在代码中加了个计时:
在这里插入图片描述
用时233秒近4分钟才获取到结果441684627。既然拿到了正确结果,我们便可以直接找妹子去了 考虑如何进一步优化求解算法。

算法优化

最初我们想的是在范围内每个数字中计算3的次数,现在换一种思路,我们计算特定范围内3在每一位上出现的次数,最后求和,这样结果也是3出现的总次数。

在这里插入图片描述
先看3在第一位(亿位)上的次数:
在这里插入图片描述
计算次数即第二位起每一位可能的选项数目相乘,此处将10连乘7次再乘个5,即 (10的7次方)x5;

第二位(千万位)上的次数:
在这里插入图片描述
第一位是0-8共9种可能,所以次数是 9x(10的6次方)x5;

第三位(百万位)上的次数:
在这里插入图片描述
前两位是0-86共87种可能,所以是 87x(10的5次方)x5;

第四位(十万位)上的次数:
在这里插入图片描述
这里要注意,因为原数前四位时8662,所以前三位是866时第四位不能为3,故前三位的范围扣掉866这种情况为0-865,最终次数是 866x(10的4次方)x5;

第五位(万位)上的次数:
在这里插入图片描述
前四位是0-8662共8663种可能,所以是 8663x(10的3次方)x5;

第六位(千位)上的次数:
在这里插入图片描述
前五位是0-86627共86628种可能,所以是 86628x(10的2次方)x5;

第七位(百位)上的次数:
在这里插入图片描述
这里也要注意,因为原数前七位时8662781,所以前六位是866278时第七位不能为3,故前六位的范围扣掉866278这种情况:866278x10x5;

第八位(十位)上的次数:
在这里插入图片描述
前七位是0-8662781共8662782种可能,所以是 8662782x5;

第九位(个位)上的次数:
在这里插入图片描述
最后也要注意,因为原数866278171,所以前八位是86627817时最后一位不能为3,故前八位的范围扣掉86627817这种情况,次数为86627817;

最后将以上九种情况相加,即可计算结果。

编码优化

以此思路为模板来总结,对86627817范围内的奇数,我们要对其第n位上的数字进行一个是否小于3的判断,若第n位小于3,则其前n-1位数字的可能性便要减少一次。以此得出第n位上3出现的次数,即 (前n-1位可能次数)x(第n+1位及之后每位的总可能数),用代码实现:
在这里插入图片描述
最后结果与之前穷举算法结果一致,同时优化过的算法运行结果大概是0.000087秒。

当然,我人工优化算法的这个过程远超之前穷举代码的233秒,但是优化的意义在于提高效率,再遇到类似的问题只需调整几个参数便可直接获取结果。例如求866278171范围内所有偶数中出现2的次数、范围内所有数中出现3的次数等问题。

其他思路及实现

此前我还有另一种思路,同样也是计算每位上出现3的次数,但要先对范围进行分段,以降低计算的复杂度。按此思路甚至可以手算出结果:
在这里插入图片描述
将其编码实现:
在这里插入图片描述
根据结果可见随着计算复杂度的降低代码耗时也更短。

缘分降临

好了,经过这么久、这么辛苦地计算,咱也可以理直气壮地加妹子好友发答案,然后期待缘分降临了!

在这里插入图片描述
最终还是躲不过

HR的套路

卒。。。

PS: 也推一下我记录学习 Python、前端 以及 微信小程序开发的公众号~
在这里插入图片描述

发布了70 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_40796925/article/details/98042642