阿里巴巴的一道笔试题

来源:互联网 发布:最好的java教程 编辑:程序博客网 时间:2024/05/01 03:43
问题描述:
12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?

问题分析:
我们先把这12个人从低到高排列,然后,选择6个人排在第一排,那么剩下的6个肯定是在第二排.
用0表示对应的人在第一排,用1表示对应的人在第二排,那么含有6个0,6个1的序列,就对应一种方案.
比如000000111111就对应着
第一排:0 1 2 3 4 5
第二排:6 7 8 9 10 11
010101010101就对应着
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
问题转换为,这样的满足条件的01序列有多少个.
观察1的出现,我们考虑这一个出现能不能放在第二排,显然,在这个1之前出现的那些0,1对应的人
要么是在这个1左边,要么是在这个1前面.而肯定要有一个0的,在这个1前面,统计在这个1之前的0和1的个数.
也就是要求,0的个数大于1的个数.
OK,问题已经解决.
如果把0看成入栈操作,1看成出栈操作,就是说给定6个元素,合法的入栈出栈序列有多少个.
这就是catalan数,这里只是用于栈,等价地描述还有,二叉树的枚举,多边形分成三角形的个数,圆括弧插入公式中的方法数,其通项是c(2n, n)/(n+1). 关于catalan数的证明以及应用请看catalan数在笔试题中的应用

下面用代码来枚举验证:

#include<stdio.h>/*计算n中1的个数*/int bit_cnt(int n){int result = 0;while(n){result++;n=n&(n-1);}return result;}int main(){int F[6],B[6];/*F代表前排,B代表后排*/int ans = 0,i,j,k,state,ok;for(state = 0; state < (1<<12);state++){if(bit_cnt(state)==6){i = 0;j = 0;for(k = 0; k < 12; k++){if(state&(1<<k))F[i++] = k;elseB[j++] = k;}ok = 1;for(k = 0; k < 6;k++){if(B[k] < F[k]){ok = 0;break;}}ans += ok;}}printf("%d\n",ans);return 0;}

运行结果:132
而c(12, 6)/7 = 12*11*10*9*8*7/(7*6*5*4*3*2) = 132
注意:c(2n, n)/(n+1) = c(2n, n) - c(2n, n-1)