JZ23 二叉搜索树的后序遍历序列

JZ23 二叉搜索树的后序遍历序列

描述

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

示例

输入:

[4,8,6,12,16,14,10]

返回值:

true

解析

二叉搜索树( Binary Search Tree )的特点为左子树的值均小于根节点的值,右子树的值均大于根节点的值,在后序遍历序列中,数组末尾即是根节点的值,因此可以将遍历序列分为三部分

  1. 数组最后一个,是根节点的值
  2. 从头开始遍历数组,遇到第一个大于根节点的值时停止
  3. 该位置左边就是左子树,右边就是右子树

划分出左右子树后,就可以根据二叉搜索树的性质判断它是否合法了,即继续遍历右子树序列,若没有值小于根节点的值(右子树的值都得大于根节点的值),则目前的结构是正确的(指目前根节点、左子树、右子树三部分,此处还未深入到整棵树)。

其中,二叉搜索树中的子树都是二叉搜索树,即对划分出的左子树和右子树进行递归判断,就可知这整棵树是否为二叉搜索树。此处与 JZ17 树的子结构 类似,都要进行递归判断子树,所以可知返回值格式应该是

	return Function(left) && Function(right);

代码清单

public class Solution {
    // 外部函数入口
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence.length == 0) return false;
        // 目前整个序列都是二叉搜索树
        return PostOrder(sequence,0,sequence.length-1);        
    }
    
    public boolean PostOrder(int [] sequence,int start,int end){
        // start = end 时,数组只有一个元素,即没有叶子的根节点
        // start > end 时,数组只有一半的元素,即根节点和它的左子树或右子树,另一半为空
        if( start >= end ) return true;
        int root = sequence[end];
        int s = start;
        // 从第一个比根节点大的点开始,划分左右子树
        while(sequence[s] < root){
            s++;
        }
        // mid 所在的位置区分了左右子树
        int mid = s;
        // 继续遍历检查右子树,必须得比根节点大
        int m = mid;
        while(m < end){
            if(sequence[m] < root){
                return false;
            }
            m++;
        }
        // 递归判断该树的左右子树是否合法
        return PostOrder(sequence,start,mid-1) && PostOrder(sequence,mid,end-1);
    }
}

递归问题都要思考一个关键问题:何时结束递归。在本题中,当传入的数组缩小到只有一个元素时,即 start == end,说明这是没有叶子的根节点,此时可以停止递归,返回 true

还有另外一种情况,在如下用例中出现

[4,6,7,5]

这种情况是我一开始也没有考虑到的。首先 5 是此树的根节点,4 为左子树,6 7 为右子树;在递归时,传入的子树数组为 [6,7],此时我们可以知道这颗子树的右子树是为空的!

但程序划分该子树的左右子树时,由于其没有右子树,分割位置 mid 会被置于与 end 相同的位置(若没有左子树则与 start 相同),导致在判断其子树 PostOrder(sequence,mid,end-1) 时(或 PostOrder(sequence,start,mid-1) ),传入的参数中 start 是大于 end 的!

这个信号表明,某节点只有一半的子树,但这一半的子树是合法的(否则在递归到它之前就已经 return false 了),这也符合二叉搜索树的情况,所以在结束递归的条件中,除了 start == end,还要有 start > end,即

        // start = end 时,数组只有一个元素,即没有叶子的根节点
        // start > end 时,数组只有一半的元素,即根节点和它的左子树或右子树,另一半为空
        if( start >= end ) return true;

这就是这种思路解决本题的关键!

总结

树的问题难免涉及树的遍历,在之前确实没说错。这题与之前相似,都要通过递归判断树的结构是否符合条件,温故知新了属于是!

上一篇:[hdu5306]Gorgeous Sequence


下一篇:disruptor笔记之八:知识点补充(终篇)