23.二叉搜索树的后序遍历序列

题目描述

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

思路:

 二叉搜索树的根节点大于所有左子树结点,小于所有右子树结点,后序遍历的 顺序是 左 -> 右 -> 根,所以最后的元素是根节点,中间第一个不小于 根节点的元素是右子树的第一个结点,继续遍历右半段数组,判断是否所有元素都大于根节点,如果都大于,则右半段作为右子树,否则直接返回false,最后根据找到的左右子树分界点,递归判断左右子树
 1 class Solution {
 2     
 3     public boolean verifyPostorder(int[] postorder) {
 4 
 5         return helpVerifyPostorder(postorder, 0, postorder.length - 1);
 6     }
 7 
 8     // 辅助函数,判断数组的某个区间是否符合后序遍历序列
 9     public boolean helpVerifyPostorder(int[] postorder, int left, int right){
10         if(right - left <= 1){  // 任意两个数都能构成搜索树的后序遍历序列
11             return true;
12         }
13         // 找到右边界作为根节点
14         // 左边界开始遍历数组,找到第一个大于根节点的元素,这前半段元素作为左子树
15         int mid = left;
16         for(mid = left; mid < right && postorder[mid] < postorder[right]; mid++);
17 
18         // 继续遍历右半段数组,判断是否所有元素都大于根节点
19         // 如果都大于,则右半段作为右子树,否则直接返回false
20         for(int i = mid; mid < right; mid++){
21             if(postorder[mid] < postorder[right]){
22                 return false;
23             }
24         }
25 
26         // 递归判断左右子树
27         return helpVerifyPostorder(postorder, left, mid - 1) && helpVerifyPostorder(postorder, mid, right - 1);
28     }
29 }

leetcode运行时间为2ms, 空间为36.3MB

复杂度分析:

时间复杂度:其实这个思路过程有点像快速排序的过程,都是对一个区间的数组选定某元素作为主元后,根据主元将该区间的所有元素划分为左右集合,最终继续递归左右集合,所以这个算法复杂度也和快速排序复杂度比较像,都是O(nlogn), 但是当前算法的思路有一个剪枝的过程,如果再判断右子区间的元素存在小于根节点的,说明整棵树不是二叉树的后序遍历序列,直接返回false, 所以该算法的时间复杂度可能会比快速排序的时间复杂度好一些。

空间复杂度:取决于递归栈的深度,栈的深度取决于数组对应的数的高度,树高最大为O(n), 最小为O(logn), 所以空间复杂度最大为O(n), 最小为O(logn)

 还有一种单调栈的方式,但是不太看得懂

先把题解贴一下,以后有时间再来看:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/solution/dan-diao-di-zeng-zhan-by-shi-huo-de-xia-tian/

使用单调栈记录和更新余下元素的上界,然后检查是否存在不符合上界约束的元素。