废话很少说,先上题目:javascript
有一个 n × m 的网格,左下角为A,右上角为B,规定每次只能走一步,而且方向只能是向上或者向右,求A到B共有多少种走法?(例如一个日字形的格子就是一个2 × 1的网格,共有3种走法)并用Javascript写出程序算法。java
你们能够先思考一下怎么作,再去看个人方法。算法
这个问题我想了好久,一直在走弯路,其实用一个抽象的数学方法就能够很轻松解决这个问题。函数
如今你能够把向右移动想象成记录一个数字1,把向上移动抽象成记录一个数字0,而且这些数字是按顺序排列的。code
看到这里我相信聪明的小伙伴已经想到了如何解决这个问题。ip
这个问题能够抽象成n个0和m个1的不一样排列的总数。好比2 × 2的网格就是2个0和2个1的全部不一样排列的数量,也就是1100,1010,1001,0110,0101,0011。get
进而,咱们能够把问题抽象成从(m + n)个0中,随意抽取m个0并将它改成1的不一样方法数,是否是以为问题很熟悉,没错!就是高中的排列组合。我先把公式亮出来?:数学
C(m, n + m) = (n + m)!/(m! * n!)
想先复习一下排列组合知识的同窗能够参见下一节。io
以上的结果用JS的描述,以下:function
function getMethods(n, m) { // 定义一个求阶乘的辅助函数 function factorial(x) { if (x === 0) { return 1 } else { return factorial(x -1) * x } } return factorial(m + n)/(factorial(m) * factorial(n)) }
若是小伙伴有好的算法,能够留言交流!
简单地讲一下排列和组合。
先举个栗子(如下n,m均为正整数),从n个含有标有不一样数字小球的袋子里,按顺序抽取n个小球,且抽取后再也不放入袋子里。第一次抽的时候,有n种可能;第二次抽的时候有n - 1种可能,以此类推,抽完n个小球总共的不一样排列个数为n!。
若是条件不变,只把抽取的小球个数改成m(m <= n)个,结果也就变成:
n × (n - 1) × (n - 2) × ... × (n - m + 1) 整理一下即: A(m, n) = n! / (n - m)!
一样是n个标记不一样数字的小球放入一个袋子中,也是抽取m个,可是此时不算抽取的顺序。也就是把排列的结果n!/(n - m)!再除以m个小球随机排列的总方法术,即m!,因此结果为:
C(m, n) = A(m, n) / m! = n! / ( (n - m)! × m! )
运用以上的知识,能够总结出如下公式:
C(m, n + m) = A(m, n + m) / m! = (n + m)! / ( n! × m! )