一道阿里巴巴的面试题.
题目是这样的:12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
所以自己也考虑了一个算法,也在网上看到别人的不同的算法。感觉我这个算法遍历效率很高,而且也很简洁(不敢用最来形容,怕强中更有强中手,当然如果能推导出公式来求解的话肯定会比我这个算法快,这个公式是F(n) = (n! / ((n/2)! * (n/2)!))/ (n/2 +1)).
我的算法思想是这样的:
(1)把排队的问题转换成数字排列问题,类似于0- 11这12个数排成2行。
(2)可以只考虑前一排的情况,因为只要前一排是符合某些条件,剩余的数按顺序放后排自然能满足条件。
(3)第一排数要符合的条件是:
下面数值表示的是位置,
0 1 2 3 4 5
6 7 8 9 10 11
对于位置0,可能的数的范围是0
对于位置1,可能的数的范围是1,2
对于位置2,可能的数的范围是2,3,4
对于位置3,可能的数的范围是3,4,5,6
对于位置4,可能的数的范围是4,5,6,7,8
对于位置5,可能的数的范围是5,6,7,8,9,10
这样可以推导出:
对于位置为n的数,其数的范围是[n, 2n].
这样对于0-5的位置的数的范围就是[{0,1,2,3,4,5}, {0,2,4,6,8,10}],
我们把这个0-5的位置的数当成一个大的数来看待,对其进行++操作,只不过进位的时候是按每个位置的数的范围来进行进位。
其实可以看成是一个枚举,并且可以用一部分的DP思想,来保存中间结果
===== 这个解法看不懂。。。 =====
首先把问题抽象,题目变成:给定一组整数,这组整数中每个数值大小不一样,把这组整数分成两组,每组按照从小到大排列,要求一组每个成员数值比对应位置上的另外一组的成员数值小。
再进一步分解抽象:就是给定一组整数,从这整数中找X个整数出来,使得这X个数之和不大于给定整数数组之和的一半,如果这个一半的情况找到了,另外一半基本确定,因此,现在题目转化成从给定数组中找一个X个数,使得X个数之和小于给定数组之和的一半。
既然问题抽象了,那么现在来设计算法,一个最简单的算法就是穷举,人脑简直是太有限了,让计算机穷举去贝,这里采用遍历整个数组,即确定一个首元素后采用栈来确定这个栈里面的元素是否符合上文中X个数的情况,如果符合就记录下来,如果不符合就进入下一步选择。具体算法是:
(1)先对给定数组Q排序,按照从小到大的顺序排列。
(2)然后循环这个数组(其时排序后循环一半就可以了,理由是找小的一半数组H,最小的元素肯定小于1/2长度的那个元素),把这个循环中的整数A1加入一个栈S,然后从给定数组Q中找比栈顶元素次大的一个元素最为下一个栈顶元素入栈,循环入栈操作。
(3)符合情况的记录:如果这个栈S的元素长度达到给定数组Q元素长度的一半时,就要判断这个栈S元素之和是否小于Q数组之和的一半,如果符合就记录这个栈S的所有元素,并弹出栈顶元素Top,从Q数组中找下一个入栈元素,条件时这个入栈元素要比这个出栈元素Top大
(4)不符合半组H的情况:当栈S元素长度等于Q数组长度一半时,并且此时出栈元素是最后一个了(排序后最大的元素),那么就要出栈两个元素;当栈S元素长度等于Q数组长度一半时,并且此时栈S元素之和已大于给定数组Q之和的一半了,也要出栈两个元素;
(5)退出循环情况:当栈S只有小于等于一个元素了,且下一个元素为空,那么退出当前循环;当栈S小于等于两个元素长度,且下一个元素为数组Q最后一个元素时,那么退出当前循环;当栈S大于两个元素长度,且下一个元素为数组Q最后一个元素时,那么要出栈两个元素。
=====
排列组合解法,是看成catalan数。
只要从12个人中挑选6个人放在第一排,那么所有的人的位置就都确定了,因为是要求按身高排序的。
这里我们的挑选方法以及限制条件是这样的:12个人先从矮到高排序,然后每个人被选到第一排或者第二排,
如果要满足题意,当且仅当每挑选完一次之后,第二排中的人数不多于第一排中的人数,(这个姑且算对吧。。。)
而这个条件的排列就是 C(12,6) - C(12,5) = 132 ,(那这个又怎么解释?)
卡塔兰数的一般项公式为
另一个表达形式为
1 Cn表示所有包含n组括号的合法运算式的个数:((())) ()(()) ()()() (())() (()())
2 Cn表示有n个节点组成不同构二叉树的方案数。
证明:
令1表示进栈,0表示出栈,则可转化为求一个2n位、含n个1、n个0的二进制数,满足从左往右扫描到任意一位时,经过的0数不多于1数。显然含n个1、n个0的2n位二进制数共有个,下面考虑不满足要求的数目。
考虑一个含n个1、n个0的2n位二进制数,扫描到第2m+1位上时有m+1个0和m个1(容易证明一定存在这样的情况),则后面的0-1排列中必有n-m个1和n-m-1个0。将2m+2及其以后的部分0变成1、1变成0,则对应一个n+1个0和n-1个1的二进制数。反之亦然(相似的思路证明两者一一对应)。
从而。证毕。
3 Cn表示所有在n × n格点中不越过对角线的单调路径的个数。
4 Cn表示通过连结顶点而将n + 2边的凸多边形分成三角形的方法个数。
6 Cn表示集合{1, ..., n}的不交叉划分的个数.