有关排列组合的一道算法题

有关排列组合的一道算法题

一、题目内容

废话不多说,先上题目:

有一个 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! )

你可能感兴趣的:(javascript,算法,递归,排列组合)