最近有一些思考,发现都可以总结为:要解决一个问题,先假设问题已经得到解决。我恍然大悟,这是一种以终为始的态度,以前只是听到以终为始,现在对这个词有了自己的理解。

我的多篇文章里,反复提到测试驱动开发,在写实现代码之前,先把测试写出来,这个潜台词就是说:假设这个功能已经实现了,那么下面这段代码将如何如何表现。

在《世界上有哪些代码量很少,但很牛逼很经典的算法案例?》中,也是这个思路,假设已经找到了衡量字符串结构的方法,那么问题就只剩下对使用这个衡量方法得到的结果是否相同这个判断了,因此首先实现了 equalBy 方法。(等等,问什么不先写 equalBy 的测试用例,然后再写它的实现?这个我的确偷懒了,因为它实现太简单,而且我太有信心了,所以直接写了实现代码。但是后面的 structure 方法,就写了针对性的测试。)

最近拿了个复旦大学的在职研究生学位,学了什么都忘了,但是清晰记得第一节课的场景。那是章忠志老师的《计算机复杂网络》。课上老师给我们介绍汉诺塔问题(看似简单,但是实际上很多复杂的问题都可以归类到汉诺塔问题),我想了很久,找不到办法,最后老师给了提示:假设规模小一点的问题已经解决,那么只需要再往前走一步就能解决整个问题了。当然,整个问题解决后,需要再回溯到起点,但这只是多米诺骨牌,只是步骤多而已,但是每一步都变得简单了,递归而已。这个解决办法太优美了,让我记忆深刻。

几年前刷力扣上的算法题时,做过一个反转链表的题目,当时特别关注细节,记得在两个节点之间反转指针时,需要特别小心,写好了反转指针细节,只要一个循环,从头节点开始,直到最后,就完事了。虽然实现过程是使用测试驱动开发,代码级别上实现了以终为始,但是解决这个问题的思维模式,属于明显的前向线性思维

在有了以终为始这个感悟后,我又想起这个问题,问自己,如果不用循环,可以怎么解决呢?于是就假设头节点之后的短一点的链表已经被反转了,那么问题就只剩下将头节点如何接上这个已经被反转的子链表上了,显然这非常简单。使用这种办法,我再一次实现了反转链表。实现结果非常理想,代码显著缩短,可读性明显提升。更重要的是,避开了那个要小心操作指针交换的步骤(容易让阅读代码的人费解),很让人满意。

除了写代码,这个思考方式也能应用到别的地方。比如,感受到职业危机怎么办,这时候不如想一下,假设自己没有职业危机,那么自己是什么状态?那么问题就只剩下把状态调整到位了。对面试的职位没有把握,就可以假设已经通过面试了,那么有什么经验分享给现在的自己,以及会想到那些通过面试的,甚至面试官在哪里,他们会想问什么问题,期待什么样的候选者等等。当然,这里面还有换位思考,但是设想自己已经通过了面试,能给自己很多启发。

总结:

今天纯粹分享一点感悟文字,明天分享反转链表的详细案例和代码。总的来说,以终为始的思考方式,让问题的解决变得简单而优雅。