这里用回溯法实现了 栈的出栈情况的遍历 。虽然这个题有更好的做法,但是你如果用回溯法做这道题,做完后一定会对回溯法有这更高境界的领悟,而且在整个设计算法,debug算法的过程中会感受到一种酣畅淋漓的快感。因为这个题看似很小,其实规模很大,要考虑方方面面的问题,很多很多。
上题。
输入一个序列 比如 123。你进栈的顺序必须是按照这个序列来,但是你可以这样,进1,然后在2进入前,把1出栈。所以出栈顺序就有了许多种可能。
我讲一下我一开始是怎么做的:
感觉这题很简单,直接开始码代码,发现有新的需求,直接改,一处改,处处改,bug比比皆是,而且怎么改都是错的,因为思路上就有了偏差。
正确的做法是怎样的:
做回溯法和其他的不一样,对逻辑的缜密和条理性要求更高,特别是碰到大规模的题目的时候。所以你应该做的第一件事,是,打开一个txt文档,写下你的思路。
接下来你只需要把你的文字转化成代码就可以了。由于我的思路是写给我自己看的,所以我这里重新写一下思路分析。
1.你的输入队列是1,2,3。所以我3推进去之后,后面就再也没有进栈的操作了,因为没有已经元素已经推光了,所以只需要进行出栈操作就可以了,所以这里进行统一处理。分两类情况,一,元素推光。二,元素还未推光。
2.元素未推光的情况。这里又分两种情况。当前栈是空的,当前栈是非空的。栈空,只能直接入栈(因为你元素未推光,所以肯定可以进行入栈操作)。栈非空。
3.栈非空的时候其实又有两种情况,你可以选择入栈(因为你元素未推光,所以肯定可以进行入栈操作),也可以选择出栈(栈非空)。所以我们用一个for循环,第一次执行入栈操作,当回溯回来的时候,for循环到下一个,执行出栈操作。
这样就把思路完美的分析出来了。接下来我会每一步都贴上对应的代码。
元素推光的一类情况
if (level == length) { // TODO: 2017/11/19 这里执行的是:把当前记录的出栈情况数组添加到所有情况的二维数组里,最后一起输出level == length。这里的level是我当前的层级。我什么都没入栈。level是0。每入栈一个数字,会执行递归,参数是level + 1。
length是数组的长度。这里是3。你的level是从0开始到,如果想到3,就已经加了4次。所以说这是一种元素都推光的情形。
元素未推光的一类情况-当前栈是空的
if (list.size() == 0) { list.add(inOrder[level]); back(level + 1, index); list.remove(list.size() - 1); }我这里的list是模拟的栈。栈是空的,只能入栈,所以add,然后level+1进行回溯,进入下一层。这里的index先不用管,没有影响的。当你back(level + 1, index);执行完以后,你后面的层级的所有情况都已经搞定了,所以你这里需要把你推的东西重新移除,进行另外方向的寻找同时又避免你推进去的东西影响另外的判断,因为你和另外的情况是平行的,如果你不删除这个数的话你这次操作就影响了另外的情况,会出错。所以这里是必须移除的。
元素未推光的一类情况-当前栈非空的
for (int i = 0; i < 2; i++) { if (i == 0) { list.add(inOrder[level]); back(level + 1, index); list.remove(list.size() - 1); } else { int num = list.remove(list.size() - 1); current[index] = num; back(level, index + 1); list.add(num); } }非空情况你可以推也可以不推,所以用了一个for循环,第一次弄入栈的情况,第二次回溯回来循环执行到下一个地方,就执行下面的代码块即出栈操作。
也是一样你添加了之后就要移除,移除了之后就要添加。这里出栈多了一个操作current[index] = num;就是记录下你的出栈情况,这个index初始是0,当你出了一次栈以后,在继续遍历的时候,就要把index + 1带进去,让后面的层级对你的出栈情况数组的接下来的一位进行分析。所以我们可以看到,如果是入栈,level + 1会被传进去,如果是出栈,index+1会被传进去,前者代表的是你的入栈队列处理到哪个位置了,后者代表的是你的出栈队列处理到哪个位置了。
这就没了。
如果说还有的话就是元素推光的那一类情况,数据又是怎么处理的。有兴趣可以看一下。
取得你所有出栈情况的二维数组的当前是第几行。这里从0,0开始向下找,找到第一个值不为0的数,就是我们要找的行数了。
int row = -1; //找到第一个没有被赋值过的行,这个找到的i就是pure(纯净,未赋值过的)行号 int flag = -1; for (int i = 0; i < 100; i++) { if (allPossible[i][0] == 0) { row = i; break;