1、原题:牛客网--二叉搜索树的后序遍历序列
2、分析
首先我们要明晰搜索二叉树的特性,其次是后序遍历。
1)搜索二叉树,root节点划分了左右子树,左子树的值《root《右子树的值;
2)后序遍历结果的最后一个值是root节点;
所以我们很容易想到 分治的方法:
1)先根据后序遍历的结果,得到root节点;
2)再根据root节点的值把遍历数组划分为两半,对应搜索树的左右子树,此时要满足,左子树所有值小于root,右子树所有值大于root,,如果不满足,说明这个数组不是后序遍历,返回false;
3)关于root的情况我们判断了,然后再递归采用同样的思想判断root的左右子树是不是也满足上述1)、2)条件,同时满足了,返回true;
分治代码:
/*
BST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),如果去掉最后一个元素的序列为T,那么T满足:T可以分成两段,前一段(左子树)小于x,
后一段(右子树)大于x,且这两段(子树)都是合法的后序序列。完美的递归定义 : ) 。
*/
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence.length==0) return false;
return verifyBst(sequence,0,sequence.length-1);//分治的思想
}
public boolean verifyBst(int[] sequence,int start,int end){
//递归终止条件
if(start>=end) return true;
//
int root=sequence[end];
//划分为左右两半
//左半部
int i = start;
while(sequence[i]<root){
i++;
}
//右半部,此时要保证右半部所有都比root大
int j=i;
while(j<end){
if(sequence[j]<root){
return false;
}
j++;
}
boolean left = verifyBst(sequence,start,i-1);//再递归判断左半部分是否满足
boolean right=verifyBst(sequence,i,end-1);//判断右半部分是否满足
return left&&right;
}
}
方法2:利用栈的压入、弹出序列思想:
前面有道题是“栈的压入、弹出序列”。
写这道题的例子时发现二叉树的中序序列和后序序列就满足栈的压入弹出序列关系。
即如果把中序序列当做栈的压入序列,那么后序序列是该栈的一个弹出序列。
而BST的中序是排序数组。因此将本题的序列排序作为中序序列,引用前面题的答案判断两序列是否满足上述关系即可。
public class Solution {
public boolean VerifySquenceOfBST(int [] seq) {
int[] arr = seq.clone();
Arrays.sort(arr);
return IsPopOrder(arr,seq);
}
//判断第二个序列是否可能为第一个序列的弹出顺序,引用的“栈的压入、弹出序列”题目的答案
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA.length == 0 || popA.length == 0)
return false;
Stack<Integer> s = new Stack<Integer>();
//用于标识弹出序列的位置
int popIndex = 0;
for(int i = 0; i< pushA.length;i++){
s.push(pushA[i]);
//如果栈不为空,且栈顶元素等于弹出序列
while(!s.empty() &&s.peek() == popA[popIndex]){
//出栈
s.pop();
//弹出序列向后一位
popIndex++;
}
}
return s.empty();
}
}