剑指Offer_#33_二叉搜索树的后续遍历
Contents
题目
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/
2 6
/
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
提示:
数组长度 <= 1000
思路分析
二叉搜索树(二叉查找树)
二叉查找树(BST:Binary Search Tree)是一种特殊的二叉树,它改善了二叉树节点查找的效率。二叉查找树有以下性质:
对于任意一个节点 n,
- 其左子树(left subtree)下的每个后代节点(descendant node)的值都小于节点 n 的值;
- 其右子树(right subtree)下的每个后代节点的值都大于节点 n 的值。
所谓节点 n 的子树,可以将其看作是以节点 n 为根节点的树。子树的所有节点都是节点 n 的后代,而子树的根则是节点 n 本身。
下图中展示了两个二叉树。二叉树(b)是一个二叉查找树(BST),它符合二叉查找树的性质规定。而二叉树(a),则不是二叉查找树。
![](./images/1594114120039.png)
更加详细的部分,参考二叉查找树 - sangmado - 博客园。
思路
- 后续遍历的顺序是左-右-根,即在每个子树的后续遍历序列当中,最后一个数字总是根节点的值,前面的一串数字,前半部分表示左子树,后半部分表示右子树。
- 根据BST的定义,左子树的每个节点的值都小于根节点的值,右子树的每个节点的值都大于根节点的值。我们可以据此找到后序遍历序列当中,左右子树的分界点,即:找到第一个比根节点的值大的数字,这个数就是右子树的第一个节点,它的左边的数字都是表示左子树,右边的数字都是表示右子树。
- BST的所有子树也都是BST。
根据以上几条,我们可以考虑使用递归的写法,递归判断每个节点的子树是否是BST,直到叶节点。
算法流程
辅助变量:start
和end
表示要判断的子树在后续遍历序列中的范围。
- 出口条件:
start >= end
,说明这个子树包含1个节点,或者没有节点,直接返回true
。 - 递推过程:
- 寻找左右子树的分界点:每次遇到比根节点小的值,向右移动指针
pointer
一次,直到遇到第一个大于根节点的值,这就是右子树的第一个节点的位置,将这个位置赋值给mid
。 - 从分界点遍历到根节点:从
mid
开始继续移动指针pointer
,每次遇到比根节点大的值,向右移动指针pointer
一次。
- 寻找左右子树的分界点:每次遇到比根节点小的值,向右移动指针
- 递归返回值
- 根据最后
pointer
停留的位置判断,如果是BST的后序遍历序列,那么必然pointer
指向序列的末尾,如果不是,返回false。 - 判断左右子树是否是BST。返回二者的与。
- 根据最后
解答
class Solution {
public boolean verifyPostorder(int[] postorder) {
return recur(postorder,0,postorder.length - 1);
}
public boolean recur(int[] postorder,int start,int end){
//当前子树只有一个节点(start == end) 或 当前子树是空树,一个节点都没有(start == end + 1)
if(start >= end) return true;
int pointer = start;
while(postorder[pointer] < postorder[end]) pointer++;
//右子树第一个节点
int mid = pointer;
while(postorder[pointer] > postorder[end]) pointer++;
//如果是该子树是二叉搜索树,pointer一定指向最后一个节点
if(pointer != end) return false;
return recur(postorder,start,mid - 1) && recur(postorder,mid,end - 1);
}
}