【剑指offer-C++】JZ33:二叉搜索树的后序遍历序列

【剑指offer-C++】JZ33:二叉搜索树的后序遍历序列

题目描述

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

数据范围: 节点数量 0≤n≤1000 ,节点上的值满足 1≤val≤10^5,保证节点上的值各不相同。

要求:空间复杂度 O(n) ,时间复杂度 O(n2)。

提示:
1.二叉搜索树是指父亲节点大于左子树中的全部节点,但是小于右子树中的全部节点的树。
2.该题我们约定空树不是二叉搜索树。
3.后序遍历是指按照 “左子树-右子树-根节点” 的顺序遍历。
4.参考下面的二叉搜索树,示例 1。

在这里插入图片描述

输入:[1,3,2]
返回值:true
说明:是上图的后序遍历 ,返回true 
输入:[3,1,2]
返回值:false
说明:不属于上图的后序遍历,从另外的二叉搜索树也不能后序遍历出该序列 ,因为最后的2一定是根节点,前面一定是孩子节点,可能是左孩子,右孩子,根节点,也可能是全左孩子,根节点,也可能是全右孩子,根节点,但是[3,1,2]的组合都不能满足这些情况,故返回false  
输入:[5,7,6,9,11,10,8]
返回值:true

解题思路

二叉搜索树的后序遍历序列:最直观的想法是,根据二叉树的特性,左<中<右,根据后序遍历的顺序,左-右-中,可以得知,每次根据区间的最后一个节点将区间分为左子区间和右子区间两个部分,并且判断是否左子区间的值均小于最后一个节点且右子区间的值均大于最后一个节点,如此循环往复直至区间只剩下一个元素为止则返回。

bool dfs(vector<int> &sequence,int l,int r)
{
   if(l>=r) //区间为空或者只有一个元素则为真
     return true;
   int root=sequence[r]; //中间节点
   int index; //分界点
   for(int i=l;i<r;i++)  //寻找分界点
   {
       if(sequence[i]>root)
       {
           index=i;
           break;
       }
   }
   for(int i=l;i<index;i++) //判断左子区间
   {
       if(sequence[i]>root) //一旦大于返回false
           return false;
   }
   for(int i=index;i<r;i++) //判断右子区间
   {
       if(sequence[i]<root) //一旦小于返回false
           return false;
   }
   //满足条件为左右区间均满足
   return dfs(sequence,l,index-1)&&dfs(sequence,index,r-1);
}
bool VerifySquenceOfBST(vector<int> sequence) 
{
     int n=sequence.size(); //二叉搜索树大小
     if(n==0) //空树不是二叉搜索树
        return false;
     return dfs(sequence,0,n-1); //深度优先遍历
}

idea:后序遍历顺序是左-右-根,逆序后序遍历顺序则是根-右-左,其中根节点是左子树的上限,根节点是右子树的下限。每一个节点都会入栈,如果当前节点大于上一个元素,则表明该节点是上一个元素的右孩子,反之如果当前节点小于上一个元素,则表明当前元素是某一个祖辈节点的左孩子,这时候我们需要找到该祖辈节点并且将该祖辈节点以及其右子树全部弹出栈,该祖辈节点的值将会成为新的上限,此时右子树均已经出栈了,剩下的只有左子树了,如果左子树节点大于新的上限则表明不满足条件,由于root表示上限,故root初始化为最大值INT_MAX。(单调栈思想很难想所以先模仿一回生二回熟)

bool VerifySquenceOfBST(vector<int> sequence) 
{
    int n=sequence.size(); //二叉搜索树大小
    if(n==0) //空树不是二叉搜索树
      return false;
    int root=INT_MAX; //初始化为最大值
    stack<int> st;
    for(int i=n-1;i>=0;i--) //逆序遍历
    {
       //当到达root即为右子树都判断完了只剩下左子树了
       //如果左子树大于根节点则不满足条件
       if(sequence[i]>root)
          return false;
       //如果栈不为空且栈顶元素大于当前序列元素则表明达到左子树部分
       while(!st.empty()&&st.top()>sequence[i])
       {
           //root一定是二叉树或者某个二叉子树的根节点
           root=st.top();
           //并且它的右子树节点都出栈了即只剩下左子树了
           st.pop();
           //以第三个示例为例 当到达6的时候 由于在9的下一个 
           //故不知道下一个是不是9的左右 这时root是10
       }
       //每一个元素都要进栈
       st.push(sequence[i]);
     }
     return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值