剑指offer | 面试题33:二叉搜索树的后序遍历序列

转载本文章请标明作者和出处
本文出自《Darwin的程序空间》
本文题目和部分解题思路来源自《剑指offer》第二版

在这里插入图片描述

开始行动,你已经成功一半了,献给正在奋斗的我们

题目

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

参考以下这颗二叉搜索树:
在这里插入图片描述

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

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

解题分析

要做这道题,首先我们得十分了解二叉搜索树这个数据结构;


二叉查找树(英语:Binary Search Tree),也称为 二叉搜索树、有序二叉树(Ordered Binary Tree)或排序二叉树(Sorted Binary Tree),是指一棵空树或者具有下列性质的二叉树:

若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。
二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为 O(\log n)O(logn)。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、多重集、关联数组等。

二叉查找树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉查找树的存储结构。中序遍历二叉查找树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉查找树变成一个有序序列,构造树的过程即为对无序序列进行查找的过程。每次插入的新的结点都是二叉查找树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索、插入、删除的复杂度等于树高,期望 O(\log n)O(logn),最坏 O(n)O(n)(数列有序,树退化成线性表)。

虽然二叉查找树的最坏效率是 O(n)O(n),但它支持动态查询,且有很多改进版的二叉查找树可以使树高为 O(\log n)O(logn),从而将最坏效率降至 O(\log n)O(logn),如 AVL 树、红黑树等。

横线中来源于leetcode


二叉搜索树,自然是二叉树的一种,而它最主要的特点就是,要不是一棵空树,要不这棵树上所有的节点的右边的所有节点以及子节点都比这个节点要大,并且这棵树上所有的节点的左边的所有节点以及子节点都比这个节点要小;

而二叉树的后续遍历,就是先输出左子树的内容,再输出右子树的内容,最后输出当前节点;

    public static void aftPrint(TreeNode root) {
        if (Objects.nonNull(root)) {
            aftPrint(root.left);
            aftPrint(root.right);
            System.out.println(root.val);
        }
    }

再结合,左子树比当前节点大,右子树比当前节点小来看,后序遍历的数组,最后输出的是根节点,并且数组前半部分是左子树,均比根节点小,后半部分是右子树,均比根节点大;如题中示例显示;
在这里插入图片描述

对应的后续遍历结果就是[1,3,2,6,5],5是跟节点,1,3,2是左子树,均比5小,6是右子树,比5大;
而[1,6,3,2,5],1比5小,是左子树,6比5大之后,右有一个3和2比5小,就不符合二叉搜索树的后续遍历结果,就返回False;
然后我们对根节点的左右子树都进行这个操作,一个递归的过程,最后判断是不是二叉搜索树的后序遍历序列;

代码(JAVA、Python3实现)

ps:这里笔者使用的jdk为1.8版本、python使用的3.7版本

  • java实现
class Solution {
    public boolean verifyPostorder(int[] postorder) {
        if (Objects.isNull(postorder) || postorder.length == 0) {
            return true;
        }
        return verifyPostorder(postorder,0,postorder.length - 1);
    }

    public boolean verifyPostorder(int[] postorder,int start,int end) {
        if (start > end) {
            return true;
        }
        int j;
        int num = postorder[end];
        for (j = start; j < end; j++) {
            if (postorder[j] > num) {
                break;
            }
        }
        for (int i = j + 1; i < end; i++) {
            if (postorder[i] < num) {
                return false;
            }
        }
        return verifyPostorder(postorder,j,end - 1) && verifyPostorder(postorder,start,j - 1);
    }
}
  • python实现(刚学了三天python,用python写把练练手,如果有语法不对,或者更好的写法,一定告诉我)
class Solution:
    def verify_postorder(self,postorder: List[int], left, right) -> bool:
        if left > right:
            return True
        point = left
        while point < right and postorder[point] < postorder[right]:
            point += 1

        point_1 = point + 1
        while point_1 < right:
            if postorder[point_1] < postorder[right]:
                return False
            point_1 += 1

        return self.verify_postorder(postorder, left, point - 1) and self.verify_postorder(postorder, point, right - 1)


    def verifyPostorder(self, postorder: List[int]) -> bool:
        if postorder is None or len(postorder) == 0:
            return True
        return self.verify_postorder(postorder, 0, len(postorder) - 1)


喜欢的朋友可以加我的个人微信,我们一起进步
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章