js用递归遍历多维数组_05. 判断一个序列是否为BST后序遍历序列

这个专栏一年多没更新了,奈何看到这道剑指上面的题有两种非常非常巧妙的非递归解法,在此记录并分享一下(dalao是用C++写的,我改成了Python)。

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

思路:这道题是一道经典的二叉树后序遍历题,一般拿到这种题,先去想递归解法:

  • 后序序列的顺序是左右根,因此数组的最后一位必然是根;
  • 找到根之后,比根小的部分就是左子树,比根大的部分就是右子树;
  • 递归判断左子树和右子树是否为BST。

递归法的关键在于寻找递归出口:

  • 出口1:如果递归到空树,说明判断完了,那么返回True即可
  • 出口2:找到根结点的值之后,可以划分出左右子树,如果左右子树的结点数加起来不等于全部结点数-1(即右子树右边还有比根小的值),那么这棵树则不是BST,返回False

递归解法如下:

# -*- coding:utf-8 -*-

结果报错:maximum recursion depth exceeded,果断爆栈了,看来需要优化为非递归算法。

因为右子树所有值一定比左子树所有值都大,因此每次判断完一次之后,剔除原本的根,则倒数第二个结点就是剩下所有结点的根!因此再循环判断剩下的结点即可。

代码如下

class 

时间复杂度:O(n^2), 空间复杂度:O(1),算是一种时间换空间以及可读性的方法

这个方法非常优雅,可读性强,但是一般来说,CPU资源比内存资源宝贵的多,有没有空间换时间的解法呢——二叉树的非递归后序遍历通常双栈法来实现(几种遍历里面最复杂的),这里我们就用栈来辅助,最终达到O(n)的时间复杂度和O(n)的空间复杂度。

分析:根节点实际上对左右子树形成了一个上下限约束,即左子树的上限、右子树的下限,如果我们从右往左倒序遍历这个序列,则访问顺序为:根右左

0. 首先,用一个栈来存储根;

  1. 如果当前访问的元素>栈顶,则说明当前元素可能是栈顶的右儿子,这个时候我们判断:
  • 如果当前元素>约束上限,则说明其祖辈中存在左子树>根的情况,返回False
  • 否则,当前元素就是栈顶的右儿子
  • 如果当前元素<栈顶,则说明当前元素一定是栈中某个元素(不一定是栈顶)的左儿子,这个时候我们需要找出它的父节点,它的父亲一定是栈中比它大的最小元素,同时将这个父节点的右子树中的结点全部出栈,并将该父节点的值作为新的约束上限

2. 然后将当前元素入栈。

代码实现如下:

class 

复杂度分析:空间自然为O(n),同时每个元素至少入栈一次,至多出栈一次,因此时间为O(n)。这个解法很巧妙,但是理解起来很困难,可以看看dalao的原文,里面有图解:

《剑指Offer》二叉搜索树的后序遍历序列_牛客博客​blog.nowcoder.net
8ad0e0ebcabc4ac999fdb2ef53ab0496.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值