力扣98,102,108
力扣刷题 23

力扣98、102、108

先放上原题链接:98,验证二叉搜索树102,二叉树的层序遍历108,转换有序数组为二叉搜索树
首先是第98,验证二叉搜索树,先看看题目:
42ce6329-340d-4478-8877-4b8e5ae3bffb.png
题目提供给了我们一个二叉树,需要我们来验证是不是搜索树(并没有要求需要平衡),关于二叉搜索树不了解的同学可以自行搜索。对于这道题,我的第一思路是,从下到上递归二叉树,然后得到子树的最大最小值,然后将当前节点和左右子树的最大最小值做对比。下面是我的代码,比较粗糙:

class Solution {
   public boolean isValidBST(TreeNode root) {
        int[] l=new int[]{Integer.MAX_VALUE,Integer.MIN_VALUE};
        int[] r=new int[]{Integer.MAX_VALUE,Integer.MIN_VALUE};
        boolean left ;
        if (root.left!=null){
            left=isValidBST2(root.left,l);
        }else {
            left=true;
        }

        boolean right ;
        if (root.right!=null){
            right=isValidBST2(root.right,r);
        }else {
            right=true;
        }

        int rrMin=Math.min(r[0],r[1]);
        int llMax=Math.max(l[0],l[1]);

        if (root.left!=null&&llMax>=root.val) {
            left=false;
        }
        if (root.right!=null&&rrMin<=root.val) {
            right=false;
        }
        return left && right ;
    }

    public boolean isValidBST2(TreeNode root,int[] m) {
        if (root.left == null && root.right == null) {
            m[0] = root.val;
            m[1]=root.val;
            return true;
        }

        int[] l=new int[]{Integer.MAX_VALUE,Integer.MIN_VALUE};
        int[] r=new int[]{Integer.MAX_VALUE,Integer.MIN_VALUE};

        boolean left ;
        if (root.left!=null){
            left=isValidBST2(root.left,l);
        }else {
            left=true;
        }

        boolean right ;
        if (root.right!=null){
            right=isValidBST2(root.right,r);
        }else {
            right=true;
        }

        m[0]=Math.min(m[0],root.val);

        int llMin;
        if (root.left!=null){
            llMin=Math.min(l[0],l[1]);
        }else {
            llMin=root.val;
        }

        int rrMin;
        if (root.right!=null){
            rrMin=Math.min(r[0],r[1]);
        }else {
            rrMin=root.val;
        }


        int min=Math.min(llMin,rrMin);
        m[0]=Math.min(m[0],min);

        m[1]=Math.max(m[1],root.val);
        int llMax;
        if (root.left!=null){
            llMax=Math.max(l[0],l[1]);
        }else {
            llMax=root.val;
        }
        int rrMax;
        if (root.right!=null){
            rrMax=Math.max(r[0],r[1]);
        }else {
            rrMax=root.val;
        }

        int max=Math.max(llMax,rrMax);
        m[1]=Math.max(m[1],max);

        if (root.left!=null&&llMax>=root.val) {
            left=false;
        }
        if (root.right!=null&&rrMin<=root.val) {
            left=false;
        }
        return left && right ;
    }

}

虽然代码比较长,但是其实比较好理解,其中重复的和可修剪的代码比较多。这段代码的时间复杂度是O(n),空间复杂度也是O(n),因为递归的深度可能会达到n。提交后发现使用了1ms,只击败了百分之30左右的用户。最后还是去看了官方解答,官方解答给出了两个,一个是从上至下递归查看是否满足条件,另外一个是中序遍历,看看遍历的结果是不是递增的,这个方法我觉得比较巧妙,并且实现又简单,详细可以去原链接看看,这里不给出代码了。

接下来是第102,二叉树的层序遍历,题目如下:
image-Rwvh.png
这题属于简单题,虽然官方定为中等,不过那是给基础比较薄弱或者没有接触过二叉树遍历的同学的定级,不然可以直接秒,下面是我的代码:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if (root==null) {
            return List.of();
        }

        List<List<Integer>> res = new ArrayList<>();
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        ArrayDeque<TreeNode> deque2 = new ArrayDeque<>();
        deque.addLast(root);
        while (!deque.isEmpty()) {
            List<Integer> list = new ArrayList<>();
            while (!deque.isEmpty()){
                TreeNode treeNode = deque.removeFirst();
                if (treeNode.left != null) {
                    deque2.add(treeNode.left);
                }
                if (treeNode.right != null) {
                    deque2.add(treeNode.right);
                }
                list.add(treeNode.val);
            }
            res.add(list);
            ArrayDeque<TreeNode> temp=deque2;
            deque2=deque;
            deque=temp;
        }
        return res;
    }
}

我的实现和官方不太一样,官方使用一个队列来存储节点,然后再存储每一层的节点数来达到要求。我使用两个队列,一个队列存储当前层,一个存储下一层,这样实现我觉得更清晰一些。并且时间复杂度和空间复杂度其实是一样的。

最后是第108,转换有序数组为二叉搜索树,题目如下:
21622d0d-b717-4690-83e2-c0b11abbf743.png

这题官方定为简单题,其实我感觉不太简单。如果按照平衡树来做,那就比较复杂了,平衡树旋转的代码可能大部分人都不太会(包括我,所以我准备找个时间好好学一下这些经典算法,以前学了忘了)。于是我直接看官方解答了,官方解答的方法很巧妙,他直接从数组的中间选择一个数作为根节点,然后递归的构建左右子树,这样就保证了树的平衡性。下面是我根据这个思路自己实现的代码:

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        int len = nums.length;
        TreeNode root = new TreeNode(nums[len / 2]);
        root.left = sortedArrayToBST2(nums, 0, len / 2 - 1);
        root.right = sortedArrayToBST2(nums, len / 2 + 1, len - 1);
        return root;
    }

    public TreeNode sortedArrayToBST2(int[] nums, int start, int end) {

        if (start > end) {
            return null;
        }
        if (start == end) {
            return new TreeNode(nums[start]);
        }

        int rootIndex = (start + end) / 2;

        TreeNode root = new TreeNode(nums[rootIndex]);
        root.left = sortedArrayToBST2(nums, start, rootIndex - 1);
        root.right = sortedArrayToBST2(nums, rootIndex + 1, end);
        return root;
    }
}

这题思路其实我觉得不太容易想到,我看了一下解答下的大家的评论,都认为这题比较巧妙,并且也有小伙伴试了平衡树,结果会超时。

力扣98,102,108
https://www.than.pw/archives/%E5%8A%9B%E6%89%A398%EF%BC%8C102%EF%BC%8C108
作者
than
发布于
更新于
许可