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:常规思路,递归
思路:用分治思想,递归.将nums以最大元素max为界切成两部分left和right.根的val为max,用left建立根的左子树,right建立根的右子树,如此递归进行.

/**
 * 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.size() == 0) { //若nums长度为0,递归终点
            return NULL;
        }
        int max = nums[0];  //初始时假设max是0号元素
        int max_idx = 0;
        for (int i = 0; i < nums.size(); i++) { //找到nums中max及其下标
            if (nums[i] > max) { //若找到新的max,更新
                max = nums[i];
                max_idx = i;
            }
        }
        vector<int> left(nums.begin(), nums.begin()+max_idx); //nums左半部分复制到left
        vector<int> right(nums.begin()+max_idx+1, nums.end()); //nums右半部分复制到right
        //重点来了
        TreeNode* root = new TreeNode(max); //根的val为max
        root->left = constructMaximumBinaryTree(left);  //递归处理根的左子树
        root->right = constructMaximumBinaryTree(right);  //递归处理根的右子树
        return root;  //返回根
    }
};

有几个特别蠢的地方,调了半天才发现:
1.找nums最大值的时候,一开始令下标max_idx=-1,然后编译过了,一运行就爆内存,调试才发现如果max就是0号元素的话,max_idx=-1导致vector越界.
正确的做法是,max_idx不要取一个异常值为初值,因为max不一定能找到(不更新),而应该与max元素一一对应,例如一般假设初始时max就是nums[0],然后max_idx就应该是0.这样即使没找到新的max,即max=nums[0],那么max_idx也依然是正确的.

2.不要忘了return,特别是递归函数,return作为递归的出口,特别重要!

其实也不用这么死板,按照题目给出的函数头来写,这样递归被限制得太死(只有一个参数),不如用一个辅助函数:

TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        return helper(nums, 0, nums.size() - 1); // 辅助函数 
    }
    
    //max_index denotes the index of the maximum number in range [left, right]
    TreeNode* helper(vector<int>& nums, int left, int right){
        if(left>right)return NULL;
        
        int max_index = left;
        for(int i = left; i<=right; i++){
            if(nums[i] > nums[max_index])max_index = i; 
        }
        
        TreeNode* root = new TreeNode(nums[max_index]);
        root->left = helper(nums, left, max_index - 1);
        root->right = helper(nums, max_index + 1, right);
        return root;
    }

解法2:用map,一次遍历加map插入,复杂度O(nlogn),比较难理解.
关键在于map是
有序的*,每次插入后都会按key值重新排序,这样就理解为何要与begin,end比较.

另一个关键是为何处理完左子树后要把左边部分清除,因为是按从左到右的顺序读取nums的,因此当读取到nums[i]时,其左侧的元素都已确定并处理,若不清除的话,再读入nums[i]右侧的元素,插入map后就丢失元素位置信息了(map会重新排序,切记!),因此把左侧删掉后,map中剩下的就全是右侧元素了.

最后返回rbegin,即倒数第一个元素,map中key最大的值肯定是root,为何这样用呢?也很简单,因为end是不存储信息的,所以不能返回end

TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
    map<int, TreeNode*> q = { { nums[0], new TreeNode(nums[0]) } };
    // 遍历nums,插入map
    for (auto i = 1; i < nums.size(); ++i) {
        auto it_b = q.insert({ nums[i], new TreeNode(nums[i]) }); 
        if (it_b.first != q.begin()) { // 若插入的元素在map中不是第一个,插入left tree.
            it_b.first->second->left = next(it_b.first, -1)->second;
            q.erase(q.begin(), it_b.first); // 将左边部分清除
        }
        if (next(it_b.first, 1) != q.end()) // 若插入的元素的下一个不是end,则将其下一个插入right tree.
            next(it_b.first, 1)->second->right = it_b.first->second;
    }
    return q.rbegin()->second; //返回map中最后一个(不是end)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容