题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回 true ,否则返回 false 。假设输入的数组的任意两个数字都互不相同。
数据范围: 节点数量0≤n≤1000 ,节点上的值满足1≤val≤105 ,保证节点上的值各不相同
要求:空间复杂度 O(n) ,时间时间复杂度 O(n^2)提示:
1、二叉搜索树是指父亲节点大于左子树中的全部节点,但是小于右子树中的全部节点的树。
2、该题我们约定空树不是二叉搜索树
3、后序遍历是指按照 “左子树-右子树-根节点” 的顺序遍历
4、参考下面的二叉搜索树,示例 1:
示例1
输入:[1,3,2]
返回值:true
说明:是上图的后序遍历 ,返回true
示例2
输入:[3,1,2]
返回值:false
说明:不属于上图的后序遍历,从另外的二叉搜索树也不能后序遍历出该序列 ,因为最后的2一定是根节点,前面一定是孩子节点,可能是左孩子,右孩子,根节点,也可能是全左孩子,根节点,也可能是全右孩子,根节点,但是[3,1,2]的组合都不能满足这些情况,故返回false
示例3
输入:[5,7,6,9,11,10,8]
返回值:true
解法一:递归
思路:
题目给的是后序遍历数组,借助后序遍历的特点:左右根,可知数组中的最后一个元素是树的根节点。对于二叉搜索树来看,其满足左子树的所有数都小于根节点,右子树的所有数都大于根节点。根据此特性,可以以根节点为目标值,从起始位置到 len-1 的数组区间内找到左右子树的分界点。当左子树中出现大于根节点的数时,则表明此序列不合法。之后再通过分治的思想,对左右子树进行判断。
1、找到根节点。
2、 从0到 len-1 的区间内从后向前遍历,找到第一个小于根节点的值,记为splitIndex。
3、以 splitIndex 将数组区间划分为两部分,判断左子树中若是有任一元素大于根结点的值,直接返回false。否则就继续进行递归,判断是否为合法的后序遍历序列。
代码:
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
// 处理特殊情况
if(sequence == null || sequence.length == 0){
return false;
}
return isLegal(sequence, 0, sequence.length-1);
}
// 判断是否合法
public boolean isLegal(int[] array, int left, int right){
if(left >= right){
return true;
}
//根节点
int root = array[right];
//找到左右子树的分界点
int splitIndex = right-1;
while(splitIndex >= 0 && array[splitIndex] > root){
splitIndex--;
}
//判断左子树是否合法
for (int i = left; i <= splitIndex; i++) {
if(array[i] > root){
return false;
}
}
//对左右子树进行合法性判断
return isLegal(array, left, splitIndex) && isLegal(array, splitIndex+1, right-1);
}
}
解法二:栈
思路:
这个思路是看到了别人的。对于二叉搜索树来说,其左孩子的值小于父节点,右孩子的值大于根节点,则中序遍历可得一个升序数组,且其中序遍历和后序遍历满足栈的压入和弹出。因此,可对其后序遍历的数组进行排序得到中序遍历的结果,然后再判断中序遍历和后序遍历是否满足栈的压入和弹出。
代码:
import java.util.Stack;
import java.util.Arrays;
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();
}
}