NC11 将升序数组转化为平衡二叉搜索树

描述

给出一个升序排序的数组,将其转化为平衡二叉搜索树(BST).

示例1

输入:

[-1,0,1,2]

复制返回值:

{1,0,2,-1}

先了解一下平衡二叉搜索树的特点。

二叉搜索树,它的中序遍历后的结果就是一个升序的序列;

平衡的,说明任何一个节点的左子树和右子树的高度相差不超过1。

题目中所给的是一个升序排序的数组,所以一个大体流程就是根据一个中序遍历的序列,还原出一个它对应的二叉树。因为是中序遍历的结果,所以元素的左边都是以该元素为根节点的左子树上的元素,元素的右边都是以该元素为根节点的右子树上的元素。

又因为是平衡的,所以先找出序列的中点,以中点的值生成根节点,他的左边右边相差不差过一个元素,即它的左子树和右子树的元素个数相差不超过一个,每次都安一样的策略来找根节点,即左右子树的高度相差不会超过1。

以中点的左边序列为一个新的序列,按照一样的方法生成一个平衡二叉树,该树是第一步找的根节点的左子树。

以中点的右边序列为一个新的序列,按照一样的方法生成一个平衡二叉树,该树是第一步找的根节点的右子树。

public class Solution {
    /**
     * 
     * @param num int整型一维数组 
     * @return TreeNode类
     */
    public TreeNode sortedArrayToBST (int[] nums) {
        // 判断特殊情况, 数组为空,或数组上没有元素,直接返回 null
        if (nums == null || nums.length == 0) {
            return null;
        }

        return process(nums, 0, nums.length - 1);
    }


    /**
     *
     * @param nums  整个的有序数组
     * @param left  数组的左边界, 闭区间
     * @param right 数组的右边界, 闭区间
     * @return nums[left ... right] 这个范围的数组,转成 BST 后的根节点
     */
    public TreeNode process(int[] nums, int left, int right) {
        // 左边界 比 右边界 大, 说明数组上没有元素,直接返回 null
        if (left > right) {
            return null;
        }
        // 如果只有一个元素,就把它当成根节点直接返回
        if (left == right) {
            TreeNode root = new TreeNode(nums[left]);
            return root;
        }

        // nums[left ... right] 这个数组的长度
        int len = right - left + 1;
        // nums[left ... right] 这个数组的中点下标,这个下标里的元素值就是 BST 的根节点的值
        int mid = left + len / 2;
        TreeNode root = new TreeNode(nums[mid]);
        // 找出根节点的左子树: 继续递归用这个方法,找出左子树上这个局部范围的BST的根节点
        root.left = process(nums, left, mid - 1);
        // 找出根节点的右子树: 继续递归用这个方法,找出右子树上这个局部范围的BST的根节点
        root.right = process(nums, mid + 1, right);
        return root;
    }
}

方法二,借助两个栈进行迭代

  • 维护两个stack,一个保存结果,一个保存每次迭代的左右分界点
  • 迭代每个数组每个元素,先获取当前区间,以及当前区间根节点在数组的位置
  • 构造当前结点,接着根据左右区间,分别构建左右子节点
  • 每次都要更新保存左右分界点的stack
import java.util.*;

public class Solution {
    public TreeNode sortedArrayToBST (int[] num) {
        if(num == null || num.length == 0) {
            return null;
        }
        // 保存结果
        Stack<TreeNode> res = new Stack<>();
        // 保存左右分界点
        Stack<Integer> stack = new Stack<>();
        // 初始化根节点
        TreeNode root = new TreeNode(0);
        res.push(root);
        stack.push(0);
        stack.push(num.length - 1);
        while(res.size() > 0) {
            // 获取当前区间
            int right = stack.pop();
            int left = stack.pop();
            // 当前区间根节点在数组的位置
            int mid = left + ((right - left + 1) >> 1);
            TreeNode node = res.pop();
            // 当前区间的根节点赋值
            node.val = num[mid];
            // 左区间,构建左子节点
            if(left <= mid - 1) {
                node.left = new TreeNode(0);
                // 初始化左子节点,为了下次构建二叉树
                res.push(node.left);
                stack.push(left);
                // 缩小为左区间
                stack.push(mid - 1);
            } 
            // 右区间,构建右子节点
            if(right >= mid + 1) {
                node.right = new TreeNode(0);
                res.push(node.right);
                stack.push(mid + 1);
                stack.push(right);
            }
        }
        return root;
    }
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值