【Day-32慢就是快】代码随想录-二叉树-最大二叉树

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

  • 二叉树的根是数组中的最大元素。
  • 左子树是通过数组中最大值左边部分构造出的最大二叉树。
  • 右子树是通过数组中最大值右边部分构造出的最大二叉树。

通过给定的数组构建最大二叉树,并且输出这个树的根节点。

思路


最大二叉树采用前序遍历,一般是先构造中间节点,然后是左右子树。

递归法

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<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
    node->left = constructMaximumBinaryTree(newVec);
}
  • 最大值所在的下标右区间构造右子树

判断maxValueIndex < (nums.size() - 1),确保右区间至少有一个数值。

if (maxValueIndex < (nums.size() - 1)) {
    vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
    node->right = constructMaximumBinaryTree(newVec);
}

整体代码如下:

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& 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<nums.size();i++){
            if(nums[i] > maxValue){
                maxValue = nums[i];
                maxValueIndex = i;
            }
        }
        node->val = maxValue;
        //最大值所在的下标左区间 构造左子树
        if(maxValueIndex > 0){
            vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
            node->left = constructMaximumBinaryTree(newVec);
        }

        if(maxValueIndex < (nums.size() - 1)){
            vector<int> newVec(nums.begin() + maxValueIndex + 1, nums.end());
            node->right = constructMaximumBinaryTree(newVec);
        }
        return node;
    }
};

逻辑清晰但是内存消耗大。

通过下标索引直接在原数组上操作,节省大量空间。

class Solution {
public:
    //在左闭右开区间[left, right)构造
    TreeNode* traversal(vector<int>& 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<int>& nums) {
        return traversal(nums, 0, nums.size());
    }
};

内存占用更小,不需要申请过多的vector空间。

可以发现上面的代码看上去简洁一些,主要是因为第二版其实是允许空节点进入递归,所以不用在递归的时候加判断节点是否为空。

总结


第一版代码加了if判断,为了不让空节点进入递归。

if (maxValueIndex > 0) { // 这里加了判断是为了不让空节点进入递归
    vector<int> newVec(nums.begin(), nums.begin() + maxValueIndex);
    node->left = constructMaximumBinaryTree(newVec);
}

if (maxValueIndex < (nums.size() - 1)) { // 这里加了判断是为了不让空节点进入递归
    vector<int> 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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值