255. 验证前序遍历序列二叉搜索树
问题
给定一个整数数组,你需要验证它是否是一个二叉搜索树正确的先序遍历序列。
你可以假定该序列中的数都是不相同的。
例子
思路
二叉树搜索树:左<根<右
前序遍历特点:根-左-右
-
方法1
$$$$
分治法,第一个是根,往后找到第一个比根大的是右子树的开始,如果右子树都>根,则此根是合格的,然后再检查左子树和右子树
-
方法2
$$$$
先序遍历的特点:根->左->右,如果出现递减序列,则是左子树,否则是右子树,因为右子树一定是递增的。
所以:二叉树的先序遍历满足:局部递减,总体递增,为了达到总体递增,保证递减序列的第一个元素<结束递减后的第一个元素【递减序列的第一个元素:即每个子树的根,从下往上依次用min记录,子树的右子树肯定都>根的值】
遍历数组的时候,用栈保存(栈中都是递减的),如果<min,则没保持递增,返回false,否则,如果<栈顶元素,即该结点是栈顶元素的左结点,放入栈,否则,是栈顶结点的同辈右结点,将栈里元素依次弹出,(同辈左结点,父节点),直到栈顶结点>该结点或者为空,【如:父节点的父节点】【此时栈顶元素>该结点,保持递减栈】期间保存该结点的父节点到min,则后面新的结点【以该结点为父节点,或者该结点父节点的同辈右结点】一定会>min
代码
//方法1
class Solution {
public boolean verifyPreorder(int[] arr) {
return check(arr, 0, arr.length-1);
}
public boolean check(int[] arr, int i, int j){
if(i>=j) return true;
int root = arr[i];
// k为右子树的开始下标,
int k=i+1;
while(k<=j && arr[k]<root) k++;
//验证右子树是否都>root
for(int m=k; m<=j; m++)
if(arr[m]<root) return false;
//如果根合格,看其左右子树是否合格
return check(arr,i+1,k-1) && check(arr, k, j);
}
}
//方法2
class Solution {
public boolean verifyPreorder(int[] arr) {
Stack<Integer> s = new Stack<>();
int min = Integer.MIN_VALUE;
for(int n : arr) {
//是不是总体递增的【其实此时看的是局部递增】
if(n<min) return false;
//n>栈顶,会不断弹出,否则直接push进栈
while(s.size()>0 && n>s.peek())
min = s.pop();
s.push(n);
}
return true;
}
面试题33. 二叉搜索树的后序遍历序列
思路
后序遍历:左子树-右子树-根
- 方法1
分治法,最后一个是根,往后找到第一个比根大的是右子树的开始,如果右子树都>根,则此根是合格的,然后再检查左子树和右子树
- 方法2
将后序遍历数组倒过来看,就变成了先序遍历的变种:根-右-左,就可以利用单调栈【递增栈,右是增的】
二叉树的后序遍历的翻转满足:局部递增,总体递减,为了达到总体递减,保证递增序列的第一个元素>结束递增后的第一个元素【递增序列的第一个元素:即每个子树的根,从下往上依次用max记录,子树的左子树肯定都<根的值】
遍历数组的时候,用栈保存(栈中都是递增的),如果>max,则没保持递减,返回false,否则,如果>栈顶元素,即该结点是栈顶元素的右结点,放入栈,否则,是栈顶结点的同辈左结点,将栈里元素依次弹出,(同辈右结点,父节点),直到栈顶结点<该结点或者为空,【如:父节点的父节点】【此时栈顶元素<该结点,保持递增栈】期间保存该结点的父节点到max,则后面新的结点【以该结点为父节点,或者该结点父节点的同辈左结点】一定会<max
代码
//方法1
class Solution {
public boolean verifyPostorder(int[] arr) {
return check(arr, 0, arr.length-1);
}
public boolean check(int[] arr, int i, int j) {
if(i>=j) return true;
//根为最后一个元素
int root = arr[j];
//k为右子树的开始
int k=i;
while(k<j && arr[k]<root) {
k++;
}
//检测右子树是否全部>root
for(int m=k; m<=j-1; m++) {
if(arr[m]<root)
return false;
}
return check(arr, i, k-1) && check(arr, k, j-1);
}
}
//方法2
class Solution {
public boolean verifyPostorder(int[] arr) {
// return check(arr, 0, arr.length-1);
Stack<Integer> s = new Stack<>();
int max = Integer.MAX_VALUE;
for(int i=arr.length-1; i>=0; i--) {
int n = arr[i];
if(n>max) return false;
while(s.size()>0 && n<s.peek())
max = s.pop();
s.push(n);
}
return true;
}