将有序数组转换为二叉搜索树

发布于:2025-07-05 ⋅ 阅读:(23) ⋅ 点赞:(0)

继续每日一题,今天给大家带来的还是树相关的题目

题目描述

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 平衡 二叉搜索树。

题目示例

在这里插入图片描述

在这篇文章中:《二叉树的直径》 我通过这道题目给大家说明了如何去思考树类型的题目,文章很短,建议大家可以看一下,针对所有树类型的题目均可通过前中后序遍历去实现,对于本题,首先你要知道什么是BST(二叉搜索树)

对于二叉搜索树的定义很简单,只要一棵树其中序遍历序列是有序序列,我们就认为它是一颗二叉搜索树,如果每个节点的左子树和右子树的高度差不超过 1,那么它就是一棵平衡BST

所以要实现本题,我们需要实现两个功能:

  • 构建出来的树其中序序列是有序序列
  • 每个节点的左子树和右子树的高度差不能超过 1

上面我一直在强调所有树类型的题目均可以通过BFS(层次遍历) OR DFS(前中后序遍历)去实现,关键就是找到处理节点的时机

对于本题,我们是要构建一个一个的根节点,然后关联其左右子树,所以只能选前序遍历,只有前序遍历,才能满足,先有根节点,然后再构建左右子树,同时题目中给出的条件是升序序列,BST 的中序遍历是升序的,因此我们可以以升序序列中的任一个元素作为根节点,以该元素左边的升序序列构建左子树,以该元素右边的升序序列构建右子树,这样得到的树就是一棵二叉搜索树

这样虽然可以构建BST,但是我们还需要保证平衡,所以只能选择有序数组的中间节点作为起始点,由于总是选择中间元素作为根,左子树和右子树的大小最多相差 1,从而保证树在每个节点处都是平衡的。

具体流程如下:

  • 找到数组的中间索引 mid(使用整数除法,向下取整),将 nums[mid] 作为根节点。
  • 左子树由 nums 中索引 left 到 mid-1 的子数组构建。
  • 右子树由 nums 中索引 mid+1 到 right 的子数组构建。
  • 递归基线:如果子数组的起始索引 left 大于结束索引 right,则返回 None(表示空子树)。

重复以上过程构建一个个的节点即可
核心代码如下:

    private TreeNode dfs(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
        int mid = (right + left) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = dfs(nums, left, mid - 1);
        root.right = dfs(nums, mid + 1, right);
        return root;
    }

完整代码:

    public TreeNode sortedArrayToBST(int[] nums) {
        return dfs(nums, 0, nums.length - 1);
    }

    private TreeNode dfs(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
        int mid = (right + left) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = dfs(nums, left, mid - 1);
        root.right = dfs(nums, mid + 1, right);
        return root;
    }

学会了这道题,后面还有一道关联的题目一起带着大家做一下

题目描述:

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

题目示例:
在这里插入图片描述

在上面我已经讲过了什么是BST以及平衡BST,对于本题,我们只需要保证中序遍历的时候当前元素比上一个元素大即可,所以我们需要使用一个变量来维护上一个元素的值

具体实现如下:

    static Integer lastNum;

    public static boolean isValidBST(TreeNode root) {
        lastNum = null;
        return dfs(root);
    }

    private static boolean dfs(TreeNode root) {
        if (root == null) {
            return true;
        }
        if (!dfs(root.left)) {
            return false;
        }
        int cuVal = root.val;
        if (lastNum != null
                && cuVal <= lastNum) {
            return false;
        }
        lastNum = cuVal;
        return dfs(root.right);
    }

当然你还可以通过记录中序遍历序列,然后通过该序列是否有序来判断是否是BST,只是该方法需要额外进行一次for循环遍历,无论哪一种方法其本质都是在考察树的前中后序遍历

    static List<Integer> list;

    public static boolean isValidBST(TreeNode root) {
        list = new ArrayList<>();
        dfs(root);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i) < list.get(i - 1)) {
                return false;
            }
        }
        return true;
    }

    private static void dfs(TreeNode root) {
        if (root == null) {
            return;
        }
        dfs(root.left);
        list.add(root.val);
        dfs(root.right);
    }

网站公告

今日签到

点亮在社区的每一天
去签到