出栈次序
D:做一道简单的题目
X星球特别讲究秩序,所有道路都是单行线。
一个甲壳虫车队,共16辆车,按照编号先后发车,夹在其它车流中,缓缓前行。
路边有个死胡同,只能容一辆车通过,是临时的检查站,如图所示。
X星球太死板,要求每辆路过的车必须进入检查站,也可能不检查就放行,也可能仔细检查。
如果车辆进入检查站和离开的次序可以任意交错。那么,该车队再次上路后,可能的次序有多少种?
为了方便起见,假设检查站可容纳任意数量的汽车。
显然,如果车队只有1辆车,可能次序1种;2辆车可能次序2种;3辆车可能次序5种。
M:大概题目的意思就是,16辆车都要进栈,但是进栈期间有别的车会出栈,这样车的顺序最后就会改变,问有多少种改变顺序。
Z:这是递归的算法,由于跟顺序无关,所以根本不需用到stack,解法如下:
public class Test {
public static void main(String[] args) {
System.out.println(stack(16,0));
}
private static int stack(int inStack, int atStack) { //准备进栈数,出栈数
if(inStack == 0){
return 1;
}
if(atStack == 0){
return stack(inStack-1, 1);
}
return stack(inStack-1,atStack+1)+stack(inStack, atStack-1);
}
}
答案是35357670
M:这道题有点不好理解,怎么想到用进栈和出栈做参数的呢?
Z:因为改变次序的实质就是车辆对栈 进&出。它既是整个流程的大体描述,也可以细化到每一小步的单元。
也就是说改变次序的操作就是:放进去+拿出来。而题目的已知量是 总数=16,所以要通过总数描述放进去+拿出来 的操作,就需要引入 栈中数 这个变量。
M:那怎么考虑到这条递归式子的呢?
Z:还是这道题目的 放进去+拿出来 核心要点,描述一个步骤(总数-1,栈中数+1)=放进去
,(总数不变,栈中数-1)=拿出来
。这两种情况加起来,就等于16辆车的所有排序情况。
M:那这个出口是怎么定的呢?
if(inStack == 0){
return 1;
}
if(atStack == 0){
return stack(inStack-1, 1);
}
Z:那就是对参数的考察,inStack和atStack会不断减少,而atStack会不断增多。但是减少不能少于0,所以需要给inStack和atStack设置为0的返回情况。
inStack:当要进去的车所有都进去了,那就只剩下拿出来1种操作了,所以出来的只有1种情况,返回1。
atStack:当出来的车所有都出来了,那就只剩下拿进去1种操作了,所以执行最小单位的拿进去操作stack(inStack-1, 1)
。
而因为atStack增多一个,inStack就减少一个,只要对其中一者进行了限制,另一个也就不需要进行限制了。
M:递归是一个很神奇的东西,它不需要知道过程的每一步详细步骤。只要设定一个规则,再设定一个限定出口,程序就会将所有符合的规则走一遍。
一般遇到这种规则模拟的题目,就可以考虑到使用递归。