剑指Offer_#33_二叉搜索树的后续遍历

剑指Offer_#33_二叉搜索树的后续遍历

Contents

题目

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

参考以下这颗二叉搜索树:

     5
    / 
   2   6
  / 
 1   3

示例 1:

输入: [1,6,3,2,5]
输出: false

示例 2:

输入: [1,3,2,6,5]
输出: true

提示:
数组长度 <= 1000

思路分析

二叉搜索树(二叉查找树)

二叉查找树(BST:Binary Search Tree)是一种特殊的二叉树,它改善了二叉树节点查找的效率。二叉查找树有以下性质:
对于任意一个节点 n,

  • 其左子树(left subtree)下的每个后代节点(descendant node)的值都小于节点 n 的值;
  • 其右子树(right subtree)下的每个后代节点的值都大于节点 n 的值。

所谓节点 n 的子树,可以将其看作是以节点 n 为根节点的树。子树的所有节点都是节点 n 的后代,而子树的根则是节点 n 本身。
下图中展示了两个二叉树。二叉树(b)是一个二叉查找树(BST),它符合二叉查找树的性质规定。而二叉树(a),则不是二叉查找树。


更加详细的部分,参考二叉查找树 - sangmado - 博客园

思路

  • 后续遍历的顺序是左-右-根,即在每个子树的后续遍历序列当中,最后一个数字总是根节点的值,前面的一串数字,前半部分表示左子树,后半部分表示右子树。
  • 根据BST的定义,左子树的每个节点的值都小于根节点的值,右子树的每个节点的值都大于根节点的值。我们可以据此找到后序遍历序列当中,左右子树的分界点,即:找到第一个比根节点的值大的数字,这个数就是右子树的第一个节点,它的左边的数字都是表示左子树,右边的数字都是表示右子树。
  • BST的所有子树也都是BST。

根据以上几条,我们可以考虑使用递归的写法,递归判断每个节点的子树是否是BST,直到叶节点。

算法流程

辅助变量startend表示要判断的子树在后续遍历序列中的范围。

  • 出口条件start >= end,说明这个子树包含1个节点,或者没有节点,直接返回true
  • 递推过程
    • 寻找左右子树的分界点:每次遇到比根节点小的值,向右移动指针pointer一次,直到遇到第一个大于根节点的值,这就是右子树的第一个节点的位置,将这个位置赋值给mid
    • 从分界点遍历到根节点:从mid开始继续移动指针pointer,每次遇到比根节点大的值,向右移动指针pointer一次。
  • 递归返回值
    • 根据最后pointer停留的位置判断,如果是BST的后序遍历序列,那么必然pointer指向序列的末尾,如果不是,返回false。
    • 判断左右子树是否是BST。返回二者的与。

解答

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return  recur(postorder,0,postorder.length - 1);
    }

    public boolean recur(int[] postorder,int start,int end){
        //当前子树只有一个节点(start == end) 或 当前子树是空树,一个节点都没有(start == end + 1)
        if(start >= end) return true;
        int pointer = start;
        while(postorder[pointer] < postorder[end]) pointer++;
        //右子树第一个节点
        int mid = pointer;
        while(postorder[pointer] > postorder[end]) pointer++;
        //如果是该子树是二叉搜索树,pointer一定指向最后一个节点
        if(pointer != end) return false;
        return recur(postorder,start,mid - 1) && recur(postorder,mid,end - 1);
    }
}
原文地址:https://www.cnblogs.com/Howfars/p/13262246.html