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;
}