剑指Offer:[第20天 分治算法(中等)]--->二叉搜索树的后序遍历序列


一、题目描述

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

参考以下这颗二叉搜索树:

     5
    / \
   2   6
  / \
 1   3

示例1:

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

示例2:

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

提示:

数组长度 <= 1000


二、思路分析

注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献

思路

后序遍历定义: [ 左子树 | 右子树 | 根节点 ] ,即遍历顺序为左、右、根。
二叉搜索树定义: 左子树中所有节点的值 < 根节点的值,右子树中所有节点的值 > 根节点的值,其左、右子树也分别为二叉搜索树。
在这里插入图片描述
根据二叉搜索树的定义,可以通过递归,判断所有子树的正确性(即其后序遍历是否满足二叉搜索树的定义),若所有子树都正确,则此序列为二叉搜索树的后序遍历。
递归分析:
①终止条件:当 l e f t ≥ r i g h t \rm{left \geq right} leftright,说明此子树节点数量 ≤ 1 \leq 1 1,无需判别正确性,因此直接返回true
②递推工作:
----划分左右子树:遍历后序遍历的 [ l e f t , r i g h t ] \rm{[left,right]} [left,right] 区间元素,寻找 第一个大于根节点 的节点,索引记为 i \rm{i} i。此时,可划分出左子树区间 [ l e f t , i − 1 ] \rm{[left,i-1]} [left,i1]、右子树区间 [ i , r i g h t − 1 ] \rm{[i, right - 1]} [i,right1]、根节点索引 r i g h t \rm{right} right
----判断是否为二叉搜索树:
--------定义一个变量 j = l e f t \rm{j}=left j=left,在左右子区间内进行遍历时,只要碰到一个满足条件的元素就让 l e f t + = 1 \rm{left+=1} left+=1。如果结果正确的话, j \rm{j} j 最后应该等于 r i g h t \rm{right} right
--------左子树区间 [ l e f t , i − 1 ] \rm{[left, i-1]} [left,i1]内的所有节点都应 < p o s t o r d e r [ r i g h t ] \rm{<postorder[right]} <postorder[right]。而第上面划分左右子树步骤已经保证左子树区间的正确性,因此只需要判断右子树区间即可。
--------右子树区间 [ i , r i g h t − 1 ] \rm{[i, right-1]} [i,right1]内的所有节点都应 > p o s t o r d e r [ r i g h t ] \rm{> postorder[right]} >postorder[right]。实现方式为遍历,当遇到 ≤ p o s t o r d e r [ r i g h t ] \rm{\leq postorder[right]} postorder[right] 的节点则跳出。则可通过 j = r i g h t \rm{j = right} j=right 判断是否为二叉搜索树。
③返回值:所有子树都需正确才可判定正确,因此使用 与逻辑符 & & \&\& && 连接。
---- j = r i g h t \rm{j = right} j=right:判断此树是否正确。
---- r e c u r ( l e f t , i − 1 ) \rm{recur(left, i - 1)} recur(left,i1):判断此树的左子树是否正确。
---- r e c u r ( i , r i g h t − 1 ) \rm{recur(i, right - 1)} recur(i,right1): 判断此树的右子树是否正确。
案例分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
复杂度分析:
时间复杂度 O ( N 2 ) \rm{O(N^2)} O(N2):每次调用recur(left,right)减去一个根节点,因此递归占用O(N)。最差情况下(即当树退化为链表),每轮递归都需遍历树所有节点,占用O(N)
空间复杂度 O ( N ) \rm{O(N)} O(N):最差情况下(即当树退化为链表),递归深度将达到N
注: 本题还可以采用辅助单调栈,将时间复杂度降低至 O ( N ) \rm{O(N)} O(N),后续再进行学习


三、整体代码

整体代码如下

bool recur(int* postorder, int left, int right){
    if(left >= right) return true;
    int i = left;
    while(postorder[i] < postorder[right]) i++;
    int j = i;
    while(postorder[i] > postorder[right]) i++;
    
    return i==right && recur(postorder, left, j-1) && recur(postorder, j, right-1);
}

bool verifyPostorder(int* postorder, int postorderSize){
    return recur(postorder, 0, postorderSize-1);
}

运行,测试通过
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知初与修一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值