问题
刚来到新公司,一天晚上加班跟新同事聊着聊着面试的话题,突然不知怎么的同事抛出一个问题来打赌,赌下个月的饭前。
一时上了头就来劲了,结果自以为是的以为能够轻松搞定,没想到被将了一军。问题是这样的:
经典的智力问答:一个人要走50步路,每次只能走1步,或是2步,求总共有多少种走法?
解答
当然了,要求是得给出解析解。自个兴冲冲的以为类似高中的常见题型,发现上当了。按照高中所学顶多给出前后项的关系。不过看计算机的算法执行上比原先的递归是要快些。
//原始的递归:第n步的走法数=第n-1步的走法数+第n-2步的走法数
function f2(n) {
if(n==1)return 1;
if(n == 2) return 2;
return f2(n-1)+f2(n-2);
}
得出的这个结论其实不是想当然的,因为从正反两方面思考的难度是完全不同的,这也就是为什么高中的时候觉得排列组合难学的原因。难在找到合适的思考切入点:
以本题为例:
正:
从f(n-1)到f(n)只要也只能走1步,而从f(n-2)步开始,可以走一个2步到f(n),也可以走2个1步到f(n),所以很可能未经深思熟虑的结果是:
f(n) = f(n-1) + 2*f(n-2)
而这又是错的,因为上面提到的走2个1步的走法其实就是f(n-1),为什么呢,f(n-2)走1步就到了f(n-1),所以这个走法属于f(n-1)的其中一种,所以f(n-2)的考虑中必须删除走2个一步的情况,而这在情急之下就会很容易忽略,从而得出错误的结果。
反:
从反面思考就简单很多,要想到达f(n),要么是f(n-1)一步上来的,要么是f(n-2)2步上来的,所以就是这两种的和。
f(n) = f(n-1) + f(n-2)
这种思考模式简单而方便,但是如果思考者觉得不放心,想从正反两方面都得出一致的结论,往往会浪费很多时间,反而让自己拿不定注意。更好的办法利用简单的值试试。
例如f(1)=1,f(2)=2,f(3)=f(n-1) + f(n-2)=3,而f(n) = f(n-1) + 2*f(n-2)=4,经过简单对比可以更快帮助我们找到和验证答案。
回到题目,利用高中的数列知识可以杰出相应的前后2项关系,通过程序实现递归,具体如下:
function f1(n) {
if(n==1)return 1;
if(n == 2) return 2;
return Math.pow((1+Math.sqrt(5))/2.0, n) - f1(n-1)*(Math.sqrt(5)-1)/2.0
}
典型的类斐波那契数列。
思考延伸
抛开题目本身单单来回忆类似的思维过程,在高中的排列组合和大学基于排列组合的概率论都会存在这个情况。思维方式完全决定了解题的难度。就数学本身来说,思维逻辑都是完备的,所以数学会给人以美感,那种纯粹逻辑演绎出整个世界的美感,一切都是那么确定。这在《几何原本》里被发挥到了极致,而现实中的各类问题很多是夹杂在具体的背景中,个人想要将其剥离,显露出数学模型的本质是需要很高的洞察和分析能力的。
而数学上应该开发一种专门的数学分支用以训练人的这种能力,可以叫数学建模或是其他,前者往往被少数具有计算机和数学才能的人作为参加相关竞赛的利器。
未来如果能有一套成熟的逻辑思考范式来指导人们,透过现象看到背后的本质,将会更进一步的开启逻辑思维的宝箱。
最后,感谢同事的问题,让我思考与感悟良久,与诸君共勉。
晚安