剑指Offer----二叉搜索树的后序遍历序列 (java实现)

题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

 

 

思路:

(上周四大晚上在刷这道题,那天状态不好头晕眼花,敲完代码运行自己写的样例没正确,然后没管就睡了。。想不通,我思路明明是正确的。然后有阴影了,周末没刷,今天大早上起来debug。。结果发现。。是我的选择排序写错了orz,被在我意想不到以为正确的地方坑了。改完排序,运行样例正确,直接提交牛客网,居然AC了。。我还想到另一种解法来着,等我一并说一下)

 

首先理解题意,这是一棵二叉搜索树,搜索树是什么呢?搜索树就是它的左子树的所有值<根的值<右子树的值,

也就是说,搜索树的中序遍历就是已经排好序的一组数啦。

根据这个突破口,判断后序遍历是否正确。

1. 后序遍历最后一个值为根结点,取出根的值,

在中序遍历中找到根,那么中序遍历,根的左边就是左子树,右边是右子树;即  左子树    根  右子树 

观察后序遍历,应该是 左子树  右子树   根  的顺序

2. 判断后序遍历是否正确要点:

中序遍历左子树个数 是否等于 后序遍历左子树个数

中序遍历右子树个数 是否等于 后序遍历右子树个数

后序遍历左子树的所有值 是否小于 中序遍历右子树的第一个值 (其实只判断这个条件就行,为什么?自己慢慢想,就能想到了 : 因为这个条件可以包含验证前面的)

然后递归。

以上条件有一个不满足,就输出false

 

方法一: 

直接构建左右子树进行递归

package com.xxxx;


/**
 * create by ziqiiii
 */
public class Example {


    static public void main(String[] args) {
        int [] sequence = {2,4,3,6,8,9,5};
        System.out.println(VerifySquenceOfBST(sequence));
    }

    //输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
    
    //因为是二叉搜索树,所以我们知道,它的中序遍历是从小到大有序排列的
    static  public boolean VerifySquenceOfBST(int [] sequence) {
        int len = sequence.length;
        if(len <= 0){
            return false;
        }

        int[] inOrder = new int[len];
        for(int i =0;i<len;i++){
            inOrder[i]=sequence[i];
        }

        for(int i =0;i<len;i++){ //选择排序
            int min = inOrder[i];
            int minIndex = i;
            for(int j =i+1;j<len;j++){
                if(inOrder[j]<min){
                    min = inOrder[j];
                    minIndex = j;
                }
            }
            inOrder[minIndex] = inOrder[i];
            inOrder[i]=min;
        }

        return isBST(inOrder,sequence); //递归判断是不是二叉搜索树
    }

    static public boolean isBST(int[] inOrder,int[]sequence){

        int len = inOrder.length;
        if(len == 0){
            return true;
        }
        int root = sequence[len -1]; //后序遍历最后一个值是根

        int leftLen = 0;
        while(inOrder[leftLen]<root){ //左子树的个数
            leftLen++;
        }

        if(leftLen+1<len){ //有右子树
            int rightMin = inOrder[leftLen+1]; //中序遍历右子树第一个值为最小值

            for(int i =0;i<leftLen;i++){ //搜索树中,后序遍历的左子树所有值 应该小于 中序遍历右子树的最小值
                if(sequence[i]>=rightMin){ //这里>=中的等于,是因为(假设输入的数组的任意两个数字都互不相同)
                    return false; 
                }
            }

        }

        
        int[] leftInOrder = new int[leftLen]; //构建左子树的中序遍历数组
        int[] leftSequence = new int[leftLen];//构建左子树的后序遍历数组
        for(int i =0;i<leftLen;i++){
            leftInOrder[i]=inOrder[i];
            leftSequence[i]=sequence[i];
        }
        boolean res = isBST(leftInOrder,leftSequence); //递归检查,左子树
        if(res==false){
            return false;
        }

        int rigthtLen = len - leftLen - 1;
        int[] rightInOrder = new int[rigthtLen]; //构建右子树的中序遍历数组
        int[] rightSequence = new int[rigthtLen]; //构建右子树的后序遍历数组
        for(int i =0;i<rigthtLen;i++){
            rightInOrder[i]=inOrder[i+leftLen+1]; //+1是根的个数
            rightSequence[i]=sequence[i+leftLen];
        }

        res = isBST(rightInOrder,rightSequence); //递归右子树
        if(res == false){
            return false;
        }

        return true;
    }


}

牛客网运行:

 

 

方法二:

不直接构建左右子树,

传递左右子树开始下标和长度,递归:

注意下标的选取:

package com.xxxx;


/**
 * create by ziqiiii
 */
public class Example {


    static public void main(String[] args) {
        int[] sequence = {5, 4, 3, 2, 1};  //true
        System.out.println(VerifySquenceOfBST(sequence));
    }

    //输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

    //因为是二叉搜索树,所以我们知道,它的中序遍历是从小到大有序排列的
    static public boolean VerifySquenceOfBST(int[] sequence) {
        int len = sequence.length;
        if (len <= 0) {
            return false;
        }

        int[] inOrder = new int[len];
        for (int i = 0; i < len; i++) {
            inOrder[i] = sequence[i];
        }

        for (int i = 0; i < len; i++) { //选择排序
            int min = inOrder[i]; //min为当前最小值
            int minIndex = i;  //最小值所对应的index
            for (int j = i + 1; j < len; j++) {
                if (inOrder[j] < min) {
                    min = inOrder[j];
                    minIndex = j;
                }
            }
            inOrder[minIndex] = inOrder[i]; //对换当前值与最小值
            inOrder[i] = min;
        }

        return isBST(inOrder, 0, sequence, 0, len); //递归判断是不是二叉搜索树
    }

    // inOrder:中序遍历数组,inStart:中序遍历开始数组下标,sequence:后序遍历数组, postStart:后序遍历开始数组下标,len:子树长度
    static public boolean isBST(int[] inOrder, int inStart, int[] sequence, int postStart, int len) {
        if (len == 0 || len == 1) { //子树长度只有0或1个时返回true
            return true;
        }

        int root = sequence[postStart + len - 1]; //根

        int i = inStart;
        for (; i < inStart + len && inOrder[i] != root; i++) ; //在中序遍历子树数组找根

        if (inOrder[i] != root) { //在中序遍历里没有找到根
            return false;
        }

        int lenL = i - inStart; //左子树长度
        int lenR = len - 1 - lenL; //右子树长度

        boolean res = true;
        if (lenL != 0) { //左子树存在

            res = isBST(inOrder, inStart, sequence, postStart, lenL);
            if (res == false) {
                return false;
            }

        }

        if (lenR != 0) { //右子树存在
            int minR = inOrder[inStart + lenL + 1];
            for (int j = postStart; j < postStart + lenL; j++) {
                if (sequence[j] > minR) {
                    return false;
                }
            }


            inStart = inStart + lenL + 1; //注意这里的inStart,应该是inOrder子树数组开始下标+该左子树长度+根长度
            postStart = postStart + lenL; //注意这里的postStart,应该是postOrder子树数组开始下标+该左子树长度
            res = isBST(inOrder, inStart, sequence, postStart, lenR);
            if (res == false) {
                return false;
            }
        }


        return true;
    }


}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值