有关排列组合的一道算法题
一、题目内容
废话不多说,先上题目:
有一个 n × m 的网格,左下角为A,右上角为B,规定每次只能走一步,并且方向只能是向上或者向右,求A到B共有多少种走法?(例如一个日字形的格子就是一个2 × 1的网格,共有3种走法)并用Javascript写出程序算法。
大家可以先思考一下怎么做,再去看我的方法。
二、解决方法
这个问题我想了很久,一直在走弯路,其实用一个抽象的数学方法就可以很轻松解决这个问题。
现在你可以把向右移动想象成记录一个数字1,把向上移动抽象成记录一个数字0,并且这些数字是按顺序排列的。
看到这里我相信聪明的小伙伴已经想到了如何解决这个问题。
这个问题可以抽象成n个0和m个1的不同排列的总数。比如2 × 2的网格就是2个0和2个1的所有不同排列的数量,也就是1100,1010,1001,0110,0101,0011。
进而,我们可以把问题抽象成从(m + n)个0中,随意抽取m个0并将它改为1的不同方法数,是不是觉得问题很熟悉,没错!就是高中的排列组合。我先把公式亮出来?:
C(m, n + m) = (n + m)!/(m! * n!)
想先复习一下排列组合知识的同学可以参见下一节。
三、Javascript代码描述
以上的结果用JS的描述,如下:
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! )