654. Maximum Binary Tree


Given an integer array with no duplicates. A maximum tree building on this array is defined as follow:

The root is the maximum number in the array.
The left subtree is the maximum tree constructed from left part subarray divided by the maximum number.
The right subtree is the maximum tree constructed from right part subarray divided by the maximum number.
Construct the maximum tree by the given array and output the root node of this tree.

Example 1:
Input: [3,2,1,6,0,5]
Output: return the tree root node representing the following tree:

  6
/   \

3 5
\ /
2 0

1
Note:
The size of the given array will be in the range [1,1000].

方法1: recursion

官方题解:https://leetcode.com/problems/maximum-binary-tree/solution/
huahua: https://zxi.mytechroad.com/blog/leetcode/leetcode-654-maximum-binary-tree/

思路:

Complexity

Time complexity : O(n^ 2) The function construct is called n times. At each level of the recursive tree, we traverse over all the n elements to find the maximum element. In the average case, there will be a nlogn levels leading to a complexity ofO(nlogn). In the worst case, the depth of the recursive tree can grow upto nn, which happens in the case of a sorted nums array, giving a complexity of O(n ^2 ).

Space complexity : O(n). The size of the set can grow upto n in the worst case. In the average case, the size will be nlogn for n elements in nums, giving an average case complexity of O(logn)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        if (nums.empty()) return nullptr;
        auto mx = max_element(nums.begin(), nums.end());
        TreeNode* root = new TreeNode(*mx);
        vector<int> left(nums.begin(), mx);
        vector<int> right(++mx, nums.end());
        root -> left = constructMaximumBinaryTree(left);
        root -> right = constructMaximumBinaryTree(right);
        return root;
    }
};

同样的原理,但是不需要copy的一种方法:

// Author: Huahua
class Solution {
public:            
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return makeMBT(nums, 0, nums.size());
    }
private:
    TreeNode* makeMBT(const vector<int>& nums, int begin, int end) {
        if(begin>=end) return nullptr;
        auto it = std::max_element(nums.begin() + begin, nums.begin() + end);
        TreeNode* root=new TreeNode(*it);
        int index = it - nums.begin();
        root->left = makeMBT(nums, begin, index);
        root->right = makeMBT(nums, index+1, end);
        return root;
    }
};

方法2: stack

discussion:https://leetcode.com/problems/maximum-binary-tree/discuss/106146/C%2B%2B-O(N)-solution
discussion: https://discuss.leetcode.com/topic/98454/c-9-lines-o-n-log-n-map

思路:

遍历一次nums的同时,维持一个单调栈,当遇到新的数字时,首次创造当前节点,并和当前栈顶元素比较:如果小于栈不为空,且当前栈顶大于此元素,这个节点会被连成栈顶节点的右紫薯;如果小于,栈顶会被连接成当前节点的左紫薯,并且被pop出栈,循环直到栈空或者第一个大于此元素的节点,作为当前节点的parent,并且将其连接至右侧。

Complexity

Time complexity: O(n)
Space complexity: O(n)
在这里插入图片描述

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        vector<TreeNode*> st;
        for (int i = 0; i < nums.size(); ++i)
        {
            TreeNode* cur = new TreeNode(nums[i]);
            while (!st.empty() && st.back()->val < nums[i])
            {
                cur->left = st.back();
                st.pop_back();
            }
            if (!st.empty())
                st.back()->right = cur;
            st.push_back(cur);
        }
        return st.front();
    }
};

以及同样思想的两个变种,第一种用map来实现插入位置的迅速查找,map中存入的始终是righ sub tree。第二种是用vector模拟单调栈,用二分法查找新节点的插入位置。

TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
  map<int, TreeNode*> q;
  for (int num : nums) {
    auto it = q.insert({ num, new TreeNode(num) }).first;
    if (it != q.begin()) {
      it->second->left = next(it, -1)->second;
      q.erase(q.begin(), it);
    }
    if (next(it, 1) != q.end()) next(it, 1)->second->right = it->second;
  }
  return q.rbegin()->second;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值