面试题33:二叉搜索树的后序遍历序列

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

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

     5
    / \
   2   6
  / \
 1   3

示例 1:

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

解答思路:
后序遍历的顺序是 : 左子树 | 右子树 | 根节点
二叉搜索树的性质:左子树的值都小于根节点,右子树的值都大于根节点。
采用递归分治的方式将数划分为左右子树,然后递归检查每个子树的正确性(是否满足后序遍历和二叉搜索树的性质。)
递归的流程:
1)划分左右子树:遍历数组 postorder 区间 [i, j],逐个元素与根节点 postorder[j] 比较,寻找大于根节点的值的下标 m,此时区间 [i, m-1] 为左子树,[m, j-1] 为右子树。
2)检查左右子树是否满足二叉搜索树的性质(左子树的元素小于根节点,右子树的元素大于根节点),因为左子树 [i, m -1] 在寻找大于根节点的值的下标 m 时已经检查过了,所以只需检查右子树 [m, j-1] 的元素是否大于根节点。
3)递归检查左右子树的正确性(满足后序遍历和二叉搜索树的性质)。

递归结束的条件i >= j,也就是子树中的节点数量小于等于1时,此时无需检查,返回 true

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return checkout(0, postorder.length-1, postorder);
    }

    private boolean checkout(int i, int j, int[] postorder){
        if(i >= j)
            return true;
        
        int m = j;  //如果全部元素都小于根节点,也就是没有右子树,[i, m-1]就是左子树,之前错放在 j-1 位置上。
        // 划分左右子树
        for(int k = i; k < j; k ++){
            if(postorder[k] > postorder[j]){
                m = k;
                break;
            }
        }
       
        // 检查右子树的元素是否都大于根节点
        for(int k = m; k < j; k ++)
            if(postorder[k] <= postorder[j])
                return false;
         
        // 检查左右子树是否满足后序遍历的性质和二叉搜索树的性质
        return checkout(i, m-1, postorder) && checkout(m, j-1, postorder);
    }

}

代码优化:

int m = j;
//划分左右子树
for(int k = i; k < j; k ++){
     if(postorder[k] > postorder[j]){
           m = k;
           break;
      }
}

可以改为

int m = 0;
while(postorder[m] < postorder[j])
    m++;

你可能感兴趣的:(面试题33:二叉搜索树的后序遍历序列)