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

在这里插入图片描述数组构造⼆叉树,构成平衡树是⾃然⽽然的事情。本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间。

本题其实要⽐⼆叉树:构造⼆叉树登场! 和 ⼆叉树:构造⼀棵最⼤的⼆叉树简单⼀些,因为有序数组构造⼆叉搜索树,寻找分割点就⽐较容易了。

分割点就是数组中间位置的节点。
那么为问题来了,如果数组⻓度为偶数,中间节点有两个,取哪⼀个?
取哪⼀个都可以,只不过构成了不同的平衡⼆叉搜索树。

递归

1、确定递归函数返回值及其参数
除⼆叉树节点,增加⼆叉树节点,都是⽤递归函数的返回值来完成,这样是⽐较⽅便。那么本题要构造⼆叉树,依然⽤递归函数的返回值来构造中节点的左右孩⼦。

再来看参数,⾸先是传⼊数组,然后就是左下表left和右下表right,我们在⼆叉树:构造⼆叉树登场! 中提过,在构造⼆叉树的时候尽量不要重新定义左右区间数组,⽽是⽤下表来操作原数组。

// 左闭右闭区间[left, right] 也可以左闭右开
TreeNode* traversal(vector<int>& nums, int left, int right)

2、确定递归终⽌条件

这⾥定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。
if (left > right) return nullptr;

3、确定单层递归的逻辑
⾸先取数组中间元素的位置,不难写出 int mid = (left + right) / 2; , 这么写其实有⼀个问题,就是数值越界,例如left和right都是最⼤int,这么操作就越界了,在⼆分法中尤其需要注意!
所以可以这么写: int mid = left + ((right - left) / 2);相当于是如果数组⻓度为偶数,中间位置有两个元素,取靠左边的。
但本题leetcode的测试数据并不会越界,所以怎么写都可以。但需要有这个意识!

取了中间位置,就开始以中间位置的元素构造节点,代码: TreeNode* root = new TreeNode(nums[mid]); 。
接着划分区间, root的左孩⼦接住下⼀层左区间的构造节点,右孩⼦接住下⼀层右区间构造的节点。
最后返回root节点,单层递归整体代码如下:

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

迭代法 (。。。。。)

class Solution {
public:
	TreeNode* sortedArrayToBST(vector<int>& nums) {
		if (nums.size() == 0) return nullptr;
		TreeNode* root = new TreeNode(0); // 初始根节点
		queue<TreeNode*> nodeQue; // 放遍历的节点
		queue<int> leftQue; // 保存左区间下表
		queue<int> rightQue; // 保存右区间下表
		nodeQue.push(root); // 根节点⼊队列
		leftQue.push(0); // 0为左区间下表初始位置


		rightQue.push(nums.size() - 1); // nums.size() - 1为右区间下表初始位置
		while (!nodeQue.empty()) {
			TreeNode* curNode = nodeQue.front();
			nodeQue.pop();
			int left = leftQue.front(); leftQue.pop();
			int right = rightQue.front(); rightQue.pop();
			int mid = left + ((right - left) / 2);
			curNode->val = nums[mid]; // 将mid对应的元素给中间节点
			if (left <= mid - 1) { // 处理左区间
				curNode->left = new TreeNode(0);
				nodeQue.push(curNode->left);
				leftQue.push(left);
				rightQue.push(mid - 1);
			}
			if (right >= mid + 1) { // 处理右区间
				curNode->right = new TreeNode(0);
				nodeQue.push(curNode->right);
				leftQue.push(mid + 1);
				rightQue.push(right);
			}
		}
		return root;
	}
};
		
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值