给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:
- 二叉树的根是数组中的最大元素。
- 左子树是通过数组中最大值左边部分构造出的最大二叉树。
- 右子树是通过数组中最大值右边部分构造出的最大二叉树。
通过给定的数组构建最大二叉树,并且输出这个树的根节点。
最大二叉树采用前序遍历,一般是先构造中间节点,然后是左右子树。
1. 确定递归的参数和返回值
传入的是存放元素的数组,返回该数组构造的二叉树的头结点。,返回类型是指向节点的指针。
2. 确定终止条件
递归遍历的时候,如果传入的数组大小为1,说明遍历到叶子节点了。
既然构造树,此时就应该定义一个新节点,把数组的值赋给新的节点,然后返回这个节点。
TreeNode* node = new TreeNode(0);
if (nums.size() == 1) {
node->val = nums[0];
return node;
}
3. 确定单层递归的逻辑
int maxValue = 0;
int maxValueIndex = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > maxValue) {
maxValue = nums[i];
maxValueIndex = i;
}
}
TreeNode* node = new TreeNode(0);
node->val = maxValue;
这里要判断maxValueIndex > 0,因为要保证左区间至少有一个数值。
if (maxValueIndex > 0) {
vector newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
}
判断maxValueIndex < (nums.size() - 1),确保右区间至少有一个数值。
if (maxValueIndex < (nums.size() - 1)) {
vector newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
}
整体代码如下:
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector& nums) {
TreeNode* node = new TreeNode(0);
if(nums.size() == 1){
node->val = nums[0];
return node;
}
//找到数组中最大值和对应下标
int maxValue = 0;
int maxValueIndex = 0;
for(int i=0;i maxValue){
maxValue = nums[i];
maxValueIndex = i;
}
}
node->val = maxValue;
//最大值所在的下标左区间 构造左子树
if(maxValueIndex > 0){
vector newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
}
if(maxValueIndex < (nums.size() - 1)){
vector newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
}
return node;
}
};
逻辑清晰但是内存消耗大。
通过下标索引直接在原数组上操作,节省大量空间。
class Solution {
public:
//在左闭右开区间[left, right)构造
TreeNode* traversal(vector& nums, int left, int right){
if(left >= right) return nullptr;
int maxValueIndex = left;
for(int i = left+1; i < right; i++){
if(nums[i] > nums[maxValueIndex])
maxValueIndex = i;
}
TreeNode* root = new TreeNode(nums[maxValueIndex]);
//左闭右开 [left, maxValueIndex)
root->left = traversal(nums, left, maxValueIndex);
root->right = traversal(nums, maxValueIndex+1, right);
return root;
}
TreeNode* constructMaximumBinaryTree(vector& nums) {
return traversal(nums, 0, nums.size());
}
};
内存占用更小,不需要申请过多的vector空间。
可以发现上面的代码看上去简洁一些,主要是因为第二版其实是允许空节点进入递归,所以不用在递归的时候加判断节点是否为空。
第一版代码加了if判断,为了不让空节点进入递归。
if (maxValueIndex > 0) { // 这里加了判断是为了不让空节点进入递归
vector newVec(nums.begin(), nums.begin() + maxValueIndex);
node->left = constructMaximumBinaryTree(newVec);
}
if (maxValueIndex < (nums.size() - 1)) { // 这里加了判断是为了不让空节点进入递归
vector newVec(nums.begin() + maxValueIndex + 1, nums.end());
node->right = constructMaximumBinaryTree(newVec);
}
第二版递归未加if判断,允许空节点进入递归,而且终止条件也改变为左右区间端点的判断。
遇到空节点,也就是数组大小为0,就终止了。
root->left = traversal(nums, left, maxValueIndex);
root->right = traversal(nums, maxValueIndex + 1, right);