今天翻陈皓(http://coolshell.cn)前辈的博客,看到一些有意思的题目,比如这个:http://coolshell.cn/articles/1976.html
有a,b,c,d,四个人
互相传球
从a开始传出
经过5次传球后
球回到a的手里
算总共有多少种传球的方法
下面评论里面很多高手给出了排列组合公式的算法,无奈这方面学的不好,只好在纸上画了树状图来揣摩。首先球在a手里,第一次传球a可以传给b,c,d三人。如果传给了b,那么第二次传球b可以传给a,c,d三人。我们把传球的情况画成如下的三叉树:
从树状图和下面的表格总结我们可以得出规律:
第N次传球后,球能够到达某人手里的方法数 == 第N-1次传球后,球不在某人手里的方法数 == 第N-1次传球后,球在其他人手里的方法数之和
例如:
两次传球后,球在a手里的方法数 = 一次传球后,球不在a手里的方法数 = 一次传球后,球在b,c,d手里的次数相加 = 1+1+1 = 3
两次传球后,球在c手里的方法数 = 一次传球后,球不在c手里的方法数 = 一次传球后,球在a,b,d手里的次数相加 = 0+1+1 = 2
具体表现在表格里面,也就是:下一排某个位置的数值,应该等于上一排除了该位置之外的其他位置相加之和。
例如:第三次的c位置的值 = 第二次的a,b,d之和 = 3+2+2 = 7。
所以:
经过5次传球后,回到a手里的方法数 = 4次传球后,球在b,c,d手里的方法数之和
= 4次传球后,球在b手里的方法数 + 4次传球后,球在c手里的方法数 + 4次传球后,球在d手里的方法数
= 3次传球后,球在a,c,d手里的方法数 + 3次传球后,球在a,b,d手里的方法数 + 3次传球后,球在a,b,c手里的方法数
=3次传球后 a + c + d + a + b + d + a + b + c = 3a + 2b + 2c + 2d = 18 + 14 + 14 + 14 = 60
知道求法之后,我们可以写代码实现,简单点可以写成递归调用,但是因为有重复计算所以会比较慢,要想时间和空间效率都比较好,就采用递推的方式,空间复杂度O(2n)。