一、题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 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} left≥right,说明此子树节点数量 ≤ 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,i−1]、右子树区间 [ i , r i g h t − 1 ] \rm{[i, right - 1]} [i,right−1]、根节点索引 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,i−1]内的所有节点都应 < 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,right−1]内的所有节点都应 > 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,i−1):判断此树的左子树是否正确。
---- r e c u r ( i , r i g h t − 1 ) \rm{recur(i, right - 1)} recur(i,right−1): 判断此树的右子树是否正确。
案例分析:
复杂度分析:
时间复杂度 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);
}
运行,测试通过