剑指 Offer 33. 二叉搜索树的后序遍历序列

    技术2022-07-12  78

    这道题其实就是给你一个序列让你判断一下可不可能是一棵二叉搜索树的后序遍历的序列。以如下的搜索树为例:

    递归分治

    首先第一种很容易想到的做法就是递归去做,因为根据后序遍历的性质,序列的最后一个元素就是二叉树的根节点,找到根节点之后就可以根据二叉搜索树的性质去将序列一分为二,上图中1 3 2这几个节点的值都小于根节点的值5,所以全部划分到左子树,6的值大于根节点的值,所以划分到右子树。划分好之后再递归就好了。

    第二种很妙的做法就是单调栈。评论区一位大佬提出了一个很妙的解法,那就是把后序遍历的序列给倒过来,倒过来之后就是前序遍历的镜像遍历了(镜像指的是先右子树后左子树),倒过来之后就是这样的:5 6 2 3 1。

    单调栈

    那么单调栈应该如何使用呢?首先需要知道的是,是要后一个元素大于前一个元素,那么后一个元素就是前一个元素的右子树。那么遍历中一旦出现后一个元素小于前一个元素了,那么就以为进入左子树了,这个时候就可以去找到当前节点的根节点root,那么怎么找呢?方法就是如果下一个元素比栈顶元素大,就压栈;否则的话就将栈顶元素出栈直到栈空或者栈顶元素小于当前元素: 还是看上图,最初我们将root的值初始化为无穷大,然后栈为空,序列为5 6 2 3 1。

    不断压栈,栈中元素为5, 6,直到2入栈,将栈顶元素弹出,每次弹出都将root设置为弹出值,可知最后栈为空,root值为5,然后将2入栈,现在栈中元素为2,剩下序列为3 1。

    然后再将3入栈,遇到1,在将栈中元素都弹出,然后root的值为2,再将1入栈,此时栈中元素为1,剩余序列为空,结束。

    如果在入栈过程中出现当前元素比root大的时候,则表示出现了问题,返回false,代码如下直接copy大佬的代码:

    class Solution { public boolean verifyPostorder(int[] postorder) { Stack<Integer> stack = new Stack<>(); int root = Integer.MAX_VALUE; for(int i = postorder.length - 1; i >= 0; i--) { if(postorder[i] > root) return false; while(!stack.isEmpty() && stack.peek() > postorder[i]) root = stack.pop(); stack.add(postorder[i]); } return true; } }
    Processed: 0.011, SQL: 10