算法题:剑指 Offer 33. 二叉搜索树的后序遍历序列 时空 0ms击败100.00%用户(题目+思路+代码+注释)

在这里插入图片描述

题目

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

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

     5
    / \
   2   6
  / \
 1   3

示例 1:

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

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

提示:

数组长度 <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

首先看题目,说到了是个二叉搜索树,而二叉搜索树有一个特征是大的往右放,小的往左放,且题目说了每个数字唯一则不考虑等于的情况,另外题目说了给出的数组里的数字是后序遍历,那么我们要看后序遍历的规律,先左子树再右子树,最后放根节点。那么我们可以知道数组最后一位定为根节点,然后往前找,比根节点大的肯定属于右子树,小的属于左子树,而中间必定有分界线,分开左右子树的遍历结果,也就是当我从最后一个往前找的时候,只要找到一个点比根节点小就证明我已经在左子树的区间了,那么前面的所有节点都必须小于根节点的值。向前巡逻完之后,对左右子树继续递归该检查拆子树检查前面的操作即可。这样通过递归一个大的二叉搜索树会被不断分解为小的树并被检查掉。
思路有了,再从示例数据去观察,从简单数据去推演我们的思路是否可行

[4, 8, 6, 12, 16, 14, 10]

我们可以将10定为根节点,想左走到了6的时候比10小,证明到了左子树的区间了,那么我们可以继续向前走确保前面的所有的点必须小于10(左子树的任何节点都比根节点小),走完全程没问题之后,我们拆分左右子树继续递归,左子树为[4,8,6],右子树为[12, 16, 14],继续对左右子树递归该操作。要考虑到左右子树只有1个元素的时候,以及左右子树没有了的情况。

代码

/**
     * 二分搜索树,大的往右放,小的往左放,后续遍历,根节点的右子树一定比根节点大,左子树一定比跟小
     *
     * @param postorder
     * @return
     */
    public boolean verifyPostorder(int[] postorder) {
        return check(postorder, 0, postorder.length - 1);
    }

    public boolean check(int[] postorder, int start, int end) {
        //子数节点只有一个一下了不需要解析了
        if (end <= start) {
            return true;
        }
        //根节点
        int root = postorder[end], leftTreeEnd = -1;
        //从根节点往前遍历
        for (int i = end - 1; i >= start; i--) {
            int t = postorder[i];
            if (t < root && leftTreeEnd == -1) {
                //到左子树了
                leftTreeEnd = i;
            }
            //如果左子树有比根大的则为错误
            if (leftTreeEnd != -1 && t > root) {
                return false;
            }
        }
        boolean ret = true;
        //检查左子树
        if (leftTreeEnd != -1 && leftTreeEnd > start) {
            ret &= check(postorder, start, leftTreeEnd);
        }
       //没有找到左边有大的节点(后面检查右子树的时候要用leftTreeEnd+1,当没有找到的时候应该从start,而后面取值用的leftTreeEnd+1,则可知右子树的start=leftTreeEnd+1=(start-1)+1)
        if (leftTreeEnd == -1) {
            leftTreeEnd = start - 1;
        }
       //检查右子树(条件是end -1 > leftTreeEnd+1等于end > leftTreeEnd + 2)
        if (end > leftTreeEnd + 2) {
            ret &= check(postorder, leftTreeEnd + 1, end - 1);
        }
        return ret;
    }
posted @ 2022-03-28 11:48  HumorChen99  阅读(0)  评论(0编辑  收藏  举报  来源