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

LeetCode算法网站算法题

https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/

由于二叉搜索树的性质,它中序遍历的序列就是一个所有节点有序排列的序列,所以根据这一条性质,我们进行类似二分法的递归建树!!由于是有序序列,所以我们总能保证建树的区间,从而确保树中节点数值的正确性。至于平衡性,由于每一个根节点的左子树和右子树的建树节点数都是k,k+1或者k+1,k,而且建树的操作是递归的,这样递归二分的创建可以使的每一个节点在当前建树节点的数量足够的情况下,会尽可能的拥有两个孩子节点,使得所有节点的左右子树高度相差最多不超过1,就足以保证每一个节点的正确平衡性。

下面是数学证明:

「平衡」要求它是一棵空树或它的左右两个子树的高度差的绝对值不超过 1,这很容易让我们产生这样的想法——左右子树的大小越「平均」,这棵树会不会越平衡?于是一种贪心策略的雏形就形成了:我们可以通过中序遍历将原来的二叉搜索树转化为一个有序序列,然后对这个有序序列递归建树,对于区间 [L,R]:


取 mid=(L+R)/2,即中心位置作为当前节点的值;


如果 L≤mid−1,那么递归地将区间 [L,mid−1] 作为当前节点的左子树;


如果 mid+1≤R,那么递归地将区间 [mid+1,R]作为当前节点的右子树。

「引理 A」 长度为 k 的区间与长度为 k+1 的区间(其中 k≥1)按照以上方法构造出的二叉树的最大高度差不超过 1。证明过程如下:

要证明「引理 A」即我们要证明:

 

由此我们可以证明不等式:

方法一:中序遍历,总是选择中间位置左边的数字作为根节点

class Solution
{
private:
    TreeNode*helper(vector<int>&num,int left,int right)
    {
        if(left>right)
            return nullptr;
        int mid=(left+right)/2;
        TreeNode*cur=new TreeNode(num[mid]);
       cur->left= helper(num,left,mid-1);
        cur->right=helper(num,mid+1,right);
        return cur;
    }
public:
    TreeNode* sortedArrayToBST(vector<int>& nums)
    {
        
       TreeNode*p= helper(nums,0,nums.size()-1);
        return p;
    }
};

方法二:中序遍历,总是选择中间位置右边的数字作为根节点

class Solution
{
public:
    TreeNode* sortedArrayToBST(vector<int>& nums)
    {
        return helper(nums, 0, nums.size() - 1);
    }

    TreeNode* helper(vector<int>& nums, int left, int right)
    {
        if (left > right)
        {
            return nullptr;
        }

        // 总是选择中间位置右边的数字作为根节点
        int mid = (left + right + 1) / 2;

        TreeNode* root = new TreeNode(nums[mid]);
        root->left = helper(nums, left, mid - 1);
        root->right = helper(nums, mid + 1, right);
        return root;
    }
};

方法三:中序遍历,选择任意一个中间位置数字作为根节点

class Solution
{
public:
    TreeNode* sortedArrayToBST(vector<int>& nums)
    {
        return helper(nums, 0, nums.size() - 1);
    }

    TreeNode* helper(vector<int>& nums, int left, int right)
    {
        if (left > right)
        {
            return nullptr;
        }

        // 选择任意一个中间位置数字作为根节点
        int mid = (left + right + rand() % 2) / 2;

        TreeNode* root = new TreeNode(nums[mid]);
        root->left = helper(nums, left, mid - 1);
        root->right = helper(nums, mid + 1, right);
        return root;
    }
};

三种方法是一种思路,但是最终建树的结构是不同的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值