给你一个整数数组 nums
,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
示例 1:
**输入:** nums = [-10,-3,0,5,9]
**输出:** [0,-3,9,-10,null,5]
**解释:** [0,-10,5,null,-3,null,9] 也将被视为正确答案:
![](https://assets.leetcode.com/uploads/2021/02/18/btree2.jpg)
示例 2:
**输入:** nums = [1,3]
**输出:** [3,1]
**解释:** [1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
按 严格递增 顺序排列
📺 视频题解
📖 文字题解
前言
二叉搜索树的中序遍历是升序序列,题目给定的数组是按照升序排序的有序数组,因此可以确保数组是二叉搜索树的中序遍历序列。
给定二叉搜索树的中序遍历,是否可以唯一地确定二叉搜索树?答案是否定的。如果没有要求二叉搜索树的高度平衡,则任何一个数字都可以作为二叉搜索树的根节点,因此可能的二叉搜索树有多个。
{:width=”85%”}
如果增加一个限制条件,即要求二叉搜索树的高度平衡,是否可以唯一地确定二叉搜索树?答案仍然是否定的。
{:width=”85%”}
直观地看,我们可以选择中间数字作为二叉搜索树的根节点,这样分给左右子树的数字个数相同或只相差 $1$,可以使得树保持平衡。如果数组长度是奇数,则根节点的选择是唯一的,如果数组长度是偶数,则可以选择中间位置左边的数字作为根节点或者选择中间位置右边的数字作为根节点,选择不同的数字作为根节点则创建的平衡二叉搜索树也是不同的。
{:width=”60%”}
确定平衡二叉搜索树的根节点之后,其余的数字分别位于平衡二叉搜索树的左子树和右子树中,左子树和右子树分别也是平衡二叉搜索树,因此可以通过递归的方式创建平衡二叉搜索树。
当然,这只是我们直观的想法,为什么这么建树一定能保证是「平衡」的呢?这里可以参考「1382. 将二叉搜索树变平衡 」,这两道题的构造方法完全相同,这种方法是正确的,1382 题解中给出了这个方法的正确性证明:1382 官方题解 ,感兴趣的同学可以戳进去参考。
递归的基准情形是平衡二叉搜索树不包含任何数字,此时平衡二叉搜索树为空。
在给定中序遍历序列数组的情况下,每一个子树中的数字在数组中一定是连续的,因此可以通过数组下标范围确定子树包含的数字,下标范围记为 $[\textit{left}, \textit{right}]$。对于整个中序遍历序列,下标范围从 $\textit{left}=0$ 到 $\textit{right}=\textit{nums}.\text{length}-1$。当 $\textit{left}>\textit{right}$ 时,平衡二叉搜索树为空。
以下三种方法中,方法一总是选择中间位置左边的数字作为根节点,方法二总是选择中间位置右边的数字作为根节点,方法三是方法一和方法二的结合,选择任意一个中间位置数字作为根节点。
方法一:中序遍历,总是选择中间位置左边的数字作为根节点
选择中间位置左边的数字作为根节点,则根节点的下标为 $\textit{mid}=(\textit{left}+\textit{right})/2$,此处的除法为整数除法。
{:width=”60%”}
[sol1-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public TreeNode sortedArrayToBST(int[] nums) { return helper(nums, 0, nums.length - 1); }
public TreeNode helper(int[] nums, int left, int right) { if (left > right) { return null; }
int mid = (left + right) / 2;
TreeNode root = new TreeNode(nums[mid]); root.left = helper(nums, left, mid - 1); root.right = helper(nums, mid + 1, right); return root; } }
|
[sol1-Python3]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution: def sortedArrayToBST(self, nums: List[int]) -> TreeNode: def helper(left, right): if left > right: return None
mid = (left + right) // 2
root = TreeNode(nums[mid]) root.left = helper(left, mid - 1) root.right = helper(mid + 1, right) return root
return helper(0, len(nums) - 1)
|
[sol1-C#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Solution { public TreeNode SortedArrayToBST(int[] nums) { return Helper(nums, 0, nums.Length - 1); }
public TreeNode Helper(int[] nums, int left, int right) { if (left > right) { return null; }
int mid = (left + right) / 2;
TreeNode root = new TreeNode(nums[mid]); root.left = Helper(nums, left, mid - 1); root.right = Helper(nums, mid + 1, right); return root; } }
|
[sol1-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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) / 2;
TreeNode* root = new TreeNode(nums[mid]); root->left = helper(nums, left, mid - 1); root->right = helper(nums, mid + 1, right); return root; } };
|
[sol1-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct TreeNode* helper(int* nums, int left, int right) { if (left > right) { return NULL; }
int mid = (left + right) / 2;
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root->val = nums[mid]; root->left = helper(nums, left, mid - 1); root->right = helper(nums, mid + 1, right); return root; }
struct TreeNode* sortedArrayToBST(int* nums, int numsSize) { return helper(nums, 0, numsSize - 1); }
|
[sol1-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14
| func sortedArrayToBST(nums []int) *TreeNode { return helper(nums, 0, len(nums) - 1) }
func helper(nums []int, left, right int) *TreeNode { if left > right { return nil } mid := (left + right) / 2 root := &TreeNode{Val: nums[mid]} root.Left = helper(nums, left, mid - 1) root.Right = helper(nums, mid + 1, right) return root }
|
复杂度分析
方法二:中序遍历,总是选择中间位置右边的数字作为根节点
选择中间位置右边的数字作为根节点,则根节点的下标为 $\textit{mid}=(\textit{left}+\textit{right}+1)/2$,此处的除法为整数除法。
{:width=”60%”}
[sol2-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public TreeNode sortedArrayToBST(int[] nums) { return helper(nums, 0, nums.length - 1); }
public TreeNode helper(int[] nums, int left, int right) { if (left > right) { return null; }
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; } }
|
[sol2-Python3]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution: def sortedArrayToBST(self, nums: List[int]) -> TreeNode: def helper(left, right): if left > right: return None
mid = (left + right + 1) // 2
root = TreeNode(nums[mid]) root.left = helper(left, mid - 1) root.right = helper(mid + 1, right) return root
return helper(0, len(nums) - 1)
|
[sol2-C#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Solution { public TreeNode SortedArrayToBST(int[] nums) { return Helper(nums, 0, nums.Length - 1); }
public TreeNode Helper(int[] nums, int left, int right) { if (left > right) { return null; }
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; } }
|
[sol2-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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; } };
|
[sol2-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct TreeNode* helper(int* nums, int left, int right) { if (left > right) { return NULL; }
int mid = (left + right + 1) / 2;
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root->val = nums[mid]; root->left = helper(nums, left, mid - 1); root->right = helper(nums, mid + 1, right); return root; }
struct TreeNode* sortedArrayToBST(int* nums, int numsSize) { return helper(nums, 0, numsSize - 1); }
|
[sol2-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func sortedArrayToBST(nums []int) *TreeNode { return helper(nums, 0, len(nums) - 1) }
func helper(nums []int, left, right int) *TreeNode { if left > right { return nil }
mid := (left + right + 1) / 2 root := &TreeNode{Val: nums[mid]} root.Left = helper(nums, left, mid - 1) root.Right = helper(nums, mid + 1, right) return root }
|
复杂度分析
方法三:中序遍历,选择任意一个中间位置数字作为根节点
选择任意一个中间位置数字作为根节点,则根节点的下标为 $\textit{mid}=(\textit{left}+\textit{right})/2$ 和 $\textit{mid}=(\textit{left}+\textit{right}+1)/2$ 两者中随机选择一个,此处的除法为整数除法。
{:width=”85%”}
[sol3-Java]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { Random rand = new Random();
public TreeNode sortedArrayToBST(int[] nums) { return helper(nums, 0, nums.length - 1); }
public TreeNode helper(int[] nums, int left, int right) { if (left > right) { return null; }
int mid = (left + right + rand.nextInt(2)) / 2;
TreeNode root = new TreeNode(nums[mid]); root.left = helper(nums, left, mid - 1); root.right = helper(nums, mid + 1, right); return root; } }
|
[sol3-Python3]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution: def sortedArrayToBST(self, nums: List[int]) -> TreeNode: def helper(left, right): if left > right: return None
mid = (left + right + randint(0, 1)) // 2
root = TreeNode(nums[mid]) root.left = helper(left, mid - 1) root.right = helper(mid + 1, right) return root
return helper(0, len(nums) - 1)
|
[sol3-C#]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Solution { public TreeNode SortedArrayToBST(int[] nums) { return Helper(nums, 0, nums.Length - 1); }
public TreeNode Helper(int[] nums, int left, int right) { if (left > right) { return null; }
int mid = (left + right + new Random().Next(2)) / 2;
TreeNode root = new TreeNode(nums[mid]); root.left = Helper(nums, left, mid - 1); root.right = Helper(nums, mid + 1, right); return root; } }
|
[sol3-C++]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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; } };
|
[sol3-C]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct TreeNode* helper(int* nums, int left, int right) { if (left > right) { return NULL; }
int mid = (left + right + rand() % 2) / 2;
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root->val = nums[mid]; root->left = helper(nums, left, mid - 1); root->right = helper(nums, mid + 1, right); return root; }
struct TreeNode* sortedArrayToBST(int* nums, int numsSize) { return helper(nums, 0, numsSize - 1); }
|
[sol3-Golang]1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| func sortedArrayToBST(nums []int) *TreeNode { rand.Seed(time.Now().UnixNano()) return helper(nums, 0, len(nums) - 1) }
func helper(nums []int, left, right int) *TreeNode { if left > right { return nil }
mid := (left + right + rand.Intn(2)) / 2 root := &TreeNode{Val: nums[mid]} root.Left = helper(nums, left, mid - 1) root.Right = helper(nums, mid + 1, right) return root }
|
复杂度分析