验证二叉搜索树前后序_255. 验证前序遍历序列二叉搜索树_面试题33. 二叉搜索树的后序遍历序列

255. 验证前序遍历序列二叉搜索树

问题

给定一个整数数组,你需要验证它是否是一个二叉搜索树正确的先序遍历序列。

你可以假定该序列中的数都是不相同的。

例子

验证二叉搜索树前后序_255. 验证前序遍历序列二叉搜索树_面试题33. 二叉搜索树的后序遍历序列_第1张图片

思路
二叉树搜索树:左<根<右
前序遍历特点:根-左-右

  • 方法1
    $$

    $$

    分治法,第一个是根,往后找到第一个比根大的是右子树的开始,如果右子树都>根,则此根是合格的,然后再检查左子树和右子树

  • 方法2
    $$

    $$
    验证二叉搜索树前后序_255. 验证前序遍历序列二叉搜索树_面试题33. 二叉搜索树的后序遍历序列_第2张图片
    验证二叉搜索树前后序_255. 验证前序遍历序列二叉搜索树_面试题33. 二叉搜索树的后序遍历序列_第3张图片
    先序遍历的特点:根->左->右,如果出现递减序列,则是左子树,否则是右子树,因为右子树一定是递增的。
    所以:二叉树的先序遍历满足:局部递减,总体递增,为了达到总体递增,保证递减序列的第一个元素<结束递减后的第一个元素【递减序列的第一个元素:即每个子树的根,从下往上依次用min记录,子树的右子树肯定都>根的值】
    遍历数组的时候,用栈保存(栈中都是递减的),如果该结点或者为空,【如:父节点的父节点】【此时栈顶元素>该结点,保持递减栈】期间保存该结点的父节点到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,则后面新的结点【以该结点为父节点,或者该结点父节点的同辈左结点】一定会

代码

//方法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;

    }

你可能感兴趣的:(medium,leetcode)