题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
题目解析
刚开始看这道题目的时候,比较蒙,大概是因为我一开始就直接看代码,没看到什么细节性质的提示。再读了下题目,基本明白了他的意思,主要意思就是说给你一个序列,你确认下这个序列到底是不是一个二叉搜索树的后序遍历结果。这里稍微讲下,二叉搜索树的概念:根节点为参考,比根节点大的数据在右侧,比根节点小的数据在左侧,叶子节点左子节点比父节点小,右子节点比父节点要大。
解题思路
这个题目属于二叉搜索树的一个性质的考察,懂得什么是二叉搜索树的话才可以顺利进行,否则,概念都不懂根本搞不清楚哪里作为判断的标准。我觉得这个题目而言,找到判定标准很重要的,这应该说是一个决定本题能不能真正求出的关键,那么,我给出的建议是读者在自己思考时辅助举例子的方式进行,自己测试下,根据自己定义的一个二叉搜索树得到他的后续遍历序列,然后逆向推他到底是不是一个二叉搜索树的后续遍历的结果串。
这里以4,8,6,12,16,14,10为例子,首先,根节点10,这是可以直接得到的,那么根据其性质,根节点左侧的小于10,根节点右侧的大于10,那么可以将本题中的序列,切分为两个子集,切分为子集,一般的方式可以采用递归了,因为子集和其本身都是一个集合的抽象,将子集和全集视为一个类型的对象就可以了。注意这里当切分完成后需要进行一个检查,这个检查就是:第一个大于10的后面的这些序列中必须全部大于10,否则直接返回false。再看看左侧子集,左侧子集的话主要是4,8,6这个三个,然后将其视为新的全集进行上述操作,那么将6作为新的根节点,那么6而言,将4,8切分为两个子集,然后子集内进行上面的操作。
代码实现
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence == null || sequence.length == 0) {
return false;
}
if(sequence.length == 1)
return true;
int endNum = sequence[sequence.length - 1];
int i = 0;
for(; i < sequence.length - 1; i ++) {
if(sequence[i] > endNum) {
break;
}
}
int index = i;
for(; index < sequence.length - 1; index++) {
if(sequence[index] < endNum) {
return false;
}
}
int[] smaller = null;
int[] bigger = null;
smaller = new int[i];
bigger = new int[sequence.length- i - 1];
int in = 0;
for(int j = 0; j < sequence.length - 1; j ++) {
if(j < i) {
smaller[j] = sequence[j];
} else {
bigger[in ++] = sequence[j];
}
}
if(i == 0) {
return VerifySquenceOfBST(bigger);
} else if(i == sequence.length - 1) {
return VerifySquenceOfBST(smaller);
} else {
return VerifySquenceOfBST(bigger) && VerifySquenceOfBST(smaller);
}
}
}
这个题还有优化的可能,比如上面的检查可以和查找比他大的数的index同时来进行,但是时间上并不会得到客观的提升,都是O(n),无非是代码减少了,下面是按照几个特例划分了左侧递归,右侧子集的递归,左侧和右侧都进行递归。
需要注意为空的情况,这是一个特例。其实我感觉这个特例不需要设计的,要么就在题目中说明。不过真正的项目中这个确实是要你自己去考虑到的。