左神算法学习篇1:搜索二叉树相关

在这里插入图片描述

题目

已知一个搜索二叉树后序遍历的数组posArr,请根据posArr,重建出整颗树返回新建树的头节点。

解题思路一

首先搜索二叉树BST定义,左子节点<根节点<右子节点,其次后序遍历为左右根,这些知识在之前相关文章中都已提到过。所以我们可以判断出这个posArr最右边的值为当前子树的根节点!(左右跟嘛,根节点一定在最右边),下面除去最右边的根节点后,数组剩余元素就是左右子树的节点了。那么有以下三种情况

1.数组剩余部分包含左右子树,这时需要去寻找左右子树的分界点,依据BST概念来从左向右依次遍历查找,在区间[L,R-1]中找到中点M,那么左子树就是[L,M],右子树[M+1,R-1]

2.数组剩余部分为左子树,那么这时,遍历查找后M==R-1,当前只有左子树[L,R-1],右子树为null

3.数组剩余部分为右子树遍历查找后M为初始值(因为右子树节点都是大于根节点的),这时当前只含右子树[L,R-1],左子树为null

注:方法二的代码将M初始值设为-1,后面依据查找过后M值得情况再做分别判断比较清晰。方法一则将M==L-1,这个比较巧妙,主要体现在区间只有左或右子树时,即只有左子树时,M为R-1,那么process1(posArr,M+1,R-1)正好出现左区间大于右区间返回null,当只有右子树时,M为初始值L-1,那么process1(posArr,L,M)出现左区间大于右区间情况返回null。
因为每次区间的中间分界点查找都是遍历,所以时间复杂度为O(n^2)

代码实现

	public static Node posArrayToBST(int[] posArr){
        return process1(posArr,0,posArr.length-1);
    }

    public static Node process1(int[] posArr,int L,int R){//O(n^2)
        if(L>R){
            return null;
        }
        Node head=new Node(posArr[R]);
        if (L==R){
            return head;
        }
        int M=L-1;
        for(int i=L;i<R;i++){
            if (posArr[i]<posArr[R]){
                M=i;
            }
        }
        head.left=process1(posArr,L,M);
        head.right=process1(posArr,M+1,R-1);
        return head;
    }


    public static Node process2(int[] posArr,int L,int R){//O(n^2)
        if(L>R){
            return null;
        }
        Node head=new Node(posArr[R]);
        if (L==R){
            return head;
        }
        int M=-1;
        for(int i=L;i<R;i++){
            if (posArr[i]<posArr[R]){
                M=i;
            }
        }
        if (M==-1){//>
            head.right=process2(posArr,L,R-1);
        }else if(M==R-1){
            head.left=process2(posArr,L,R-1);
        }else {
            head.left=process2(posArr,L,M);
            head.right=process2(posArr,M+1,R-1);
        }
        return head;
    }

解题思路二

下面讲解一直时间复杂度更低的解法,每次在查找左右子树的分界点时可以利用二分查找来找出分界节点。这样每次查找时间复杂度由原来的遍历O(n)变为二分的O(logn),所以总的时间复杂度为O(nlogn)

代码实现

	public static Node process3(int[] posArr,int L,int R){//O(nlogn)
        if(L>R){
            return null;
        }

        Node head=new Node(posArr[R]);
        if (L==R){
            return head;
        }
        int M=L-1;
        int left=L;
        int right=R-1;
        while (left<=right){
            int mid=left+(right-left)>>1;
            if(posArr[mid]<posArr[R]){
                M=mid;
                left=mid+1;
            }else {
                right=mid-1;
            }
        }
        head.left=process3(posArr,L,M);
        head.right=process3(posArr,M+1,R-1);
        return head;
    }

总结

算法的学习是个长期的过程,需要一直不断的去刷去总结来保持手感!

楼主断更了几个月去参加秋招,无实习、非科班、9月初 0offer…,今年内卷非常严重,很多算法的都转到后台,竞争更是大的一匹,心态不知道崩了几次,到最后自己也陆续拿了阿里、腾讯、网易互娱、京东等10多个offer吧。最大的感受还是要“平时多积累”这至关重要!这才是关键时刻自己的优势所在!

最后放上一张秋招期间给自己的桌面背景,送给各位,勉励同行!
奥利给

觉得本博客有用的客官,可以给个点赞+收藏哦! 嘿嘿

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值