题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
示例1:
输入: [1,6,3,2,5]
输出: false
示例2:
输入: [1,3,2,6,5]
输出: true
解题思路:
1、递归:
二叉搜索树的特点是节点数值的大小顺序是:left<root<right,而后序遍历的顺序是“左-右-根”,因此对一个二叉树来说,数组的最后一个数值是根节点,然后根据二叉搜索树的特点,遍历数组后可以得到左右子树的后序节点,这样通过递归地不断判断左右子树可以得出该数组是否满足某一个二叉搜索树的后序遍历。
注意点:递归的终止条件是i>=j
,而不是i==j
(这样当子树只有两个节点,即[1,2]时会出现问题)
2、单调栈:
由于二叉搜索树的特点是节点数值的大小顺序是:left<root<right
,而后序遍历的顺序是:left->right->root
,这样不具有单调性,而反转后序遍历的顺序恰好是:root->right->left
,这样对于每一个子树来说,从根节点到右孩子的数值都具有递增的性质。
这里可以使用一个单调栈来保存递增的节点,当第一次将所有递增节点保存到栈后,这样这个子树的右节点以及右节点的右节点都保存到了栈中;当栈顶元素大于当前元素后,则循环弹出栈中元素,直至栈顶元素不大于当前元素后,这个时候后面子树的根节点更新为栈顶元素,然后将当前结点存入栈中。因为后面元素都是根节点的左子树或者左子树的孩子节点,因此后面元素不能大于根节点的数字,否则就不符合某二叉搜索树的后序遍历结果。这个二叉搜索树可以初始化看成一个根节点数值为Integer.MAX_VALUE
的左子树。
实现代码:
//解法1:递归
public boolean verifyPostorder(int[] postorder) {
return recur(postorder, 0, postorder.length - 1);
}
public boolean recur(int[] postorder, int i, int j){
if(i >= j)//这里不能只写==,这样会出现数组越界错误
return true;
int m = i;
while(postorder[m] < postorder[j])
m++;
int p = m;
while(postorder[p] > postorder[j])
p++;
return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
}
//解法2:单调栈
public boolean verifyPostorder1(int[] postorder) {
Stack<Integer> stack = new Stack<>();
int root = Integer.MAX_VALUE;
for(int i = postorder.length - 1; i >= 0; i--){
if(postorder[i] > root)
return false;
while(!stack.empty() && stack.peek() > postorder[i])
root = stack.pop();//更新root
stack.add(postorder[i]);
}
return true;
}