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

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

思路:分治

由于二叉搜索树具有左子树小于根节点,右子树大于根节点的性质,通过递归判断是否为二叉搜索树。

算法流程:

  • 终止条件:当 i ≥ j i\ge j ij,说明此子树节点数量 ≤ 1 \leq 1 1,无需判别正确性,直接返回true

  • 递归工作:

    • 划分左右子树:遍历后序遍历的[i,j]区间元素,寻找第一个大于根节点的节点,索引为m,此时可以划分左子树区间为[i,m-1],右子树区间为[m,j-1],根节点索引为j
    • 分别判断左子树和右子树是否为二叉搜索树
    • 返回值:所有节点遍历完并且所有子树都正确才可判定正确
    class Solution {
    public:
        bool verifyPostorder(vector<int>& postorder) {
            return recur(postorder,0,postorder.size()-1);
        }
    
        bool recur(vector<int>& postorder,int left,int right){
            if(left>=right) return true;
            int p=left;
            while(postorder[p]<postorder[right]) ++p;
            int m=p;
            while(postorder[m]>postorder[right]) ++m;
            return m==right&&recur(postorder,left,p-1)&&recur(postorder,p,right-1);
        }
    };
    

时间复杂度 O( n 2 n^2 n2)

空间复杂度 O(n)

思路二:辅助单调栈

后序遍历的逆序:根节点|右子树|左子树。类似先序遍历的镜像。

设后序遍历倒序的列表为[ r n , r n − 1 ⋯ r 1 r_n,r_{n-1}\cdots r_1 rn,rn1r1],遍历此列表,设索引为i,若为二叉搜索树,则有:

  • 当节点值 r i > r i + 1 r_i>r_{i+1} ri>ri+1,节点 r i r_i ri在节点 r i + 1 r_{i+1} ri+1的右子节点
  • 当节点值 r i < r i + 1 r_i<r_{i+1} ri<ri+1,节点 r i r_i ri一定是某root的左子节点,且root为最接近 r i r_i ri的节点
  • 当遍历到递减节点 r i < r i + 1 r_i<r_{i+1} ri<ri+1,若为二叉搜索树,则对于后序遍历中节点 r i r_i ri右边的任意节点 r x ∈ [ r i − 1 , r i − 2 , ⋯   , r 1 ] r_x\in[r_{i-1},r_{i-2},\cdots,r_1] rx[ri1,ri2,,r1],必有节点值 r x < r o o t r_x<root rx<root

考虑使用单调栈实现遍历递减的最近的节点:

  • stack存储值递增的节点
  • 每当遇到值递减的节点 r i r_i ri,则通过出栈来更新节点 r i r_i ri的父节点root
  • 每次判断 r i r_i ri和root的值关系:
    • r i r_i ri>root说明不满足二叉搜索树的定义,返回false
    • r i r_i ri<root说明满足二叉搜索树定义,继续遍历

过程:

  • 初始化:单调栈,父节点root= + ∞ +\infty +
  • 倒序遍历:记每个节点为 r i r_i ri:
    • 判断:若 r i > r o o t r_i>root ri>root,说明不满足定义,返回false
    • 更新父节点root:当栈不为空且 r i < s t a c k . t o p ( ) r_i<stack.top() ri<stack.top()时,执行循环出栈
    • 入栈
  • 若遍历完成,说明满足定义,返回true
class Solution {
public:
    bool verifyPostorder(vector<int>& postorder) {
        stack<int> stk;
        int root=INT_MAX;
        for(int i=postorder.size()-1;i>=0;--i){
            if(postorder[i]>root)return false;
            while(stk.size()&&stk.top()>postorder[i]) {
                root=stk.top();
                stk.pop();
            }
            stk.push(postorder[i]);
        }
        return true;
    }
};

时间复杂度 O(n)

空间复杂度 O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值