?》,鲁迅先生在月光下用狂人的嘴在《狂人日记》的质问和呐喊,是的,一直都是这样,而普通人的思维模式一直都是这样。以进阶数为例,我们大概从数开始。学习泛函、抽象、拓扑等,其实就是按照标准的方式来学习。理论上,这样可以增加对已经学过的知识的理解,也可以提高对某些数点和线代数的理解。了解问题的本质会有所帮助。数学归纳法其实是一种迭代(iteration),从简单的起点,到一般的情况。递归是一种反人类的逆向思维模式。作为研究人员,掌握这种反常识的思维逻辑是非常有必要的。这里我们先讲一个推理故事:在一个下着雨的秋夜,日本警视厅搜查课警司长谷田任三郎和他的助手今泉在山路上驾车行驶。突然,汽车抛锚了。无奈之下,古畑只好下车徒步求助。被他吸引,古畑敲响了别墅的门,开门的是美丽的漫画家千千波。这是她的私人别墅。千波得知来的是刑警,便告诉了九幡一个可怕的事实。一座私人别墅的仓库内,有一具尸体。这具尸体不是别人,正是漫画出版社的编辑波多野先生。死者脸朝下躺在地上。尸体额头上有瘀伤,周围散落着一些稿纸。.他手里只拿着一张稿纸,纸上却没有留下遗言,只是一张白纸,正好旁边还有一支开着笔帽的钢笔。随后,古畑询问了千波和波多野的关系,千波表示他们只是工作上的关系。不过因为她经常来这里讨论出版事宜,所以她给了波多野一把钥匙。随后,千波微笑着解释说,波多野先生可能已经死于事故。仓库的门一旦关上,就无法从里面打开。波多野的死可能是由于不小心将自己关在里面造成的。死因是缺氧窒息。她已经一个多月没有来这栋别墅了,也是这时候,她才发现了波多野的尸体。古畑不这么认为,他怀疑这是一起谋杀。因为死者头部有伤口,还在流血。钱奈梅认为这不可能,因为门是关着的,没有钥匙是打不开的。只有她和波多野先生有别墅的钥匙。别人不可能进来砸波多野的脑袋,她已经一个多月没来了。那时候他起了疑心,觉得千波的说法不无道理。就像有一罐饼干。我们打开它,发现有人咬了一口。通常,我们假设有人在盖上盖子之前咬了一口饼干。机灵的古畑发现千波的言行可疑,便回到仓库,在死者的口袋里发现了好几张三天前的购物小票。据此,古畑分析道:死者一定知道凶手的名字,因为三天前死者和凶手一起来到了别墅,死者一定有隐藏的线索,可以揭开凶手的真相。为何死者在众多手稿中执着于这份空白手稿?明明有纸有笔,却什么也没有写。他究竟想表达什么?古畑不解地想着。这时,电闪雷鸣,房子突然断电了。千奈不禁感叹:“今夜,真是惨不忍睹!”雷雨之夜,幽深的别墅,美丽的少女,漆黑的仓库,恐怖的尸体,都显得那么的诡异和神秘。熄灭蜡烛后,我发现古畑正在看书。Guhata称赞Chinami的书是一部杰作。夜深了,两人都饿了。两人来到储藏室,女主人想也没想就拿出了鸡蛋做蛋奶汤。细心的古畑纳闷:你一个多月没来,这里的鸡蛋真的可以吃吗?回到别墅,古畑对千波说道:“请原谅我说的是实话。三天前,千波小姐和波多野先生一起来过别墅吗?”、“我上次来这里是一个月前发生的事情”千波面无表情,“你没有说实话,请问你怎么知道冰箱里的鸡蛋是新鲜的?你上次来这里不是一个月前,也就是说,你三天前把鸡蛋放进冰箱里。在我的想象中,一个不知道世界温暖的美丽漫画家和一个花花公子般的出版社编辑。我不知道你们之间发生了什么,但其中一个终于发现另一个只是在原地玩耍,于是展开了一场残酷的战斗,复仇。千波笑道:“凶手为什么要打断死者的脑袋?如果别人认为是意外,凶手是不会那么做的。对吧?可是受害人却受伤了,这就很矛盾了。所以我仔细想了想,伪装成意外的凶手和故意留下杀人证据的人不是同一个人吗?”、“有两个凶手吗?”、“只有一个凶手,我们其实忽略了很关键的一点,也就是这张白纸,死者确实留下了线索,只是我们还没有找到,线索就保存在这张白纸上。我们换个角度想,想象一下波多野先生当时的心情。他无论如何都想留下凶手的名字,可不管他怎么写下凶手的名字,只要被凶手先发现,就会被毁掉。很显然,凶手一定是第一个找到尸体的,因为凶手将他锁在了仓库里,所以他苦思冥想,先是拿起一张纸,然后取下了笔帽,可是他什么都没写你明白吗?在能写下凶手名字的情况下,他什么也没写,这就是他留下的线索。他想表达的意思是‘不管我写什么,都是没用的’。”“那他头上的伤口呢?如何解释?”“这也是波多野先生留下的线索之一。因为不管他怎么想留下蛛丝马迹,如果这个案子就当成意外来处理,那一切就都没有意义了。所以他无论如何都想留下杀人的证据,所以他给自己开了一枪。”是的,一张白纸,上面什么也没有写,就是死者留下的线索。这张白纸在无声地诉说着:杀死我的凶手,就是第一个发现我尸体的人。这个故事本身并不复杂,爱恨交织的血腥杀人案,但故事的核心是一张白纸,是死者留下的唯一线索。这条线索是具畑发现的。逆向思维。那么,从代码层面来说,递归可以帮助我们解决哪些问题呢?我们以高斯求和为例。所谓高斯求和,就是将一个阈值范围内的所有整数相加求和的算术问题。如果使用迭代逻辑:defsum_number(n):total=0foriinrange(1,n+1):total+=ireturntotal调用方法:print(sum_number(5))liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/excel_test.py"136101515liuyue:mytornadoliuyue$可以看出迭代思维的本质是增量遍历,把元素一个一个按顺序累加,这不是很难理解,那我们试试递归的解法:defsum_number(n):ifn<=0:return0returnn+sum_number(n-1)我们可以看到,当我们用递归来设计程序时,我们从最后的结果,也就是我们要求sum\_number(5),计算机会把这个计算拆解成求sum\_number(4)的操作,和给sum\_number加5的操作(4).以此类推,直到对sum\_number(1)的操作进行反汇编,才会触发终止条件,即当if结构体中n<=0时,返回具体的数字0。虽然整个递归过程非常复杂,但是在写程序的时候,我们只需要关注初始条件、终止条件和连接,而不用关注每一个具体的步骤。递归思维是自上而下的,我们做事情的时候可以先考虑整体。先明确需要达到的大目标,而不是从一开始就在细节上更加现实,这其实就是系统论的思想。很多初入职场的程序员,在不了解项目整体功能结构的情况下,急于编写代码,往往导致最后多次返工,事倍功半。但是,在使用Python设计递归程序时,需要注意栈溢出的问题。如果递归深度超过1000层会报错,所以需要单独设置递归深度:importsys#将递归深度改为100万sys.setrecursionlimit(1000000)要理解递归的简单思想,让我们尝试高级操作:尾递归。尾递归是传统递归的一个特例。在尾递归中,先进行某一部分的计算,然后调用递归,这样就可以得到当前的计算结果,而这个结果也会作为参数传递给下一次递归。这意味着函数调用出现在调用者函数的末尾。因为是结尾,所以它比传统递归有一个优势,就是不需要保存任何局部变量。在内存消耗方面,实现了节省特性:deftail_sum(n,result=0):ifn==0:returnresultelse:returntail_sum(n-1,result+n)传统递归解题步骤:5+sum_number(4)5+(4+sum_number(3))5+(4+(3+sum_number(2)))5+(4+(3+(2+sum_number(1))))5+(4+(3+(2+1)))15每次递归,程序会将计算结果存放在内存中,在递归过程中不断累加,直到递归出口。尾递归就是通过传递参数递归传递累加的结果:tail_sum(5,0)tail_sum(4,5)tail_sum(3,9)tail_sum(2,12)tail_sum(1,14)tail_sum(0,15)如果递归深度很大,可以节省很多内存开销。相关视频教程请移步:https://www.bilibili.com/video...综上所述,熟练使用递归需要注意以下三个特点:1.问题本身可以分为更简单的子问题,并且子问题可以用同样的方法求解。2、解决问题需要提前考虑程序的退出,否则就会陷入递归死循环的陷阱。3.递归不是一个非常高效的算法,大规模的问题需要尾递归的参与。结语:掌握递归和逆向思维的人,往往能找到解决一些难题的新方法,善于利用资源,找到巧妙的解决问题的方法,就像文章开头的刑警古畑。当我们面对生活和社会中的种种问题时,我们能否想象鲁迅先生发出“历来如此,理所应当”的呐喊。“总是”可能是真的,也可能不是。但作为当代人,我应该反省自己,与大家分享我的鼓励。原文转载自《刘越的技术博客》https://v3u.cn/a_id_186
