LeetCode-654. Maximum Binary Tree

本文探讨了在LeetCode上解决构建最大二叉树问题的两种方法:一种是正向思维的递归方法,效率较低;另一种是利用栈进行一次遍历的高效算法,通过维护一个降序栈来构建树,避免了递归的开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在leetcode,觉得不刷题的话,思维能力会下降。

题目:

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.自己写的:正向思维,按照正常思路写递归;效率比较低,代码如下:

/**
 * 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:
//    Runtime: 108 ms, faster than 26.14% of C++ online submissions for Maximum Binary Tree.
//    Memory Usage: 38.1 MB, less than 24.71% of C++ online submissions for Maximum Binary Tree.
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        if(nums.size() == 0)
            return nullptr;
        vector<int>::iterator it = std::max_element(nums.begin(), nums.end());
        int index = it - nums.begin();
        int max = *it;

        TreeNode *node = new TreeNode(max);
        vector<int> vecLeft;
        if(index > 0)
            vecLeft = vector<int>(nums.begin(), nums.begin() + index);
        node->left = constructMaximumBinaryTree(vecLeft);

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

2.评论中别人写的:

思路:[3,2,1,6,0,5]从左到右遍历数组,时间O(n),相当于从左到右建立树,开始建立已遍历数组的子树的条件是出现一个数比前一个数大,因此栈保存的永远是降序的数组,由于从左开始
1.左边>当前,左边的数比当前大,则当前数不会有左子树,当前->left = null,当前进栈
2.左边<当前,最大值出现,形成左子树,由于栈是降序数组,所以依次出栈,直到当前值小于栈中的值,并且->right = nullptr,栈底值为当前的左子树根,当前进栈

//    Runtime: 72 ms, faster than 97.18% of C++ online submissions for Maximum Binary Tree.
//    Memory Usage: 26.3 MB, less than 99.43% of C++ online submissions for Maximum Binary Tree.
    TreeNode* constructMaximumBinaryTree_(vector<int> &nums)
    {
        stack<TreeNode*> s;
        const auto up = [&](int x) {
            TreeNode* child = nullptr;
            while (!s.empty() && (s.top()->val <= x)) {
                s.top()->right = child;
                child = s.top();
                s.pop();
            }
            return child;
        };
        for (const auto x : nums) {
            const auto node = new TreeNode(x);
            node->left = up(x);
            s.push(node);
        }
        return up(numeric_limits<int>::max());
    }

一次遍历就解决了惯性思维中的递归,一个很好的思路。

### LeetCode 刷题推荐列表与学习路径 在 LeetCode 上进行刷题时,制定一个合理的计划非常重要。以下是一个基于算法分类的学习路径和推荐题目列表[^1]: #### 学习路径 1. **基础算法理论** 在开始刷题之前,建议先通过视频或书籍了解基本的算法理论。例如,分治法、贪心算法、动态规划、二叉搜索树(BST)、图等概念[^1]。 2. **数据结构基础** 熟悉常见的数据结构,包括数组、链表、栈、队列、哈希表、树、图等。确保对这些数据结构的操作有深刻理解。 3. **分模块刷题** 按照以下顺序逐步深入: - 树:从简单的遍历问题(如前序、中序、后序遍历)开始,逐渐过渡到复杂问题(如二叉搜索树验证、平衡二叉树等)。 - 图与回溯算法:学习图的表示方法(邻接矩阵、邻接表),并练习深度优先搜索(DFS)和广度优先搜索(BFS)。结合回溯算法解决组合问题、排列问题等。 - 贪心算法:选择一些经典的贪心问题(如活动选择问题、区间覆盖问题)进行练习。 - 动态规划:从简单的 DP 问题(如爬楼梯、斐波那契数列)入手,逐步掌握状态转移方程的设计技巧。 4. **刷题策略** 刷题时优先选择简单或中等难度的题目,并关注通过率较高的题目。这有助于建立信心并巩固基础知识[^1]。 #### 推荐题目列表 以下是按算法分类的 LeetCode 题目推荐列表: 1. **树** - [104. 二叉树的最大深度](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/) - [94. 二叉树的中序遍历](https://leetcode-cn.com/problems/binary-tree-inorder-traversal/) - [236. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) 2. **图与回溯** - [79. 单词搜索](https://leetcode-cn.com/problems/word-search/) - [51. N皇后](https://leetcode-cn.com/problems/n-queens/) - [78. 子集](https://leetcode-cn.com/problems/subsets/) 3. **贪心** - [455. 分发饼干](https://leetcode-cn.com/problems/assign-cookies/) - [135. 分发糖果](https://leetcode-cn.com/problems/candy/) - [406. 根据身高重建队列](https://leetcode-cn.com/problems/queue-reconstruction-by-height/) 4. **动态规划** - [70. 爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/) - [53. 最大子数组和](https://leetcode-cn.com/problems/maximum-subarray/) - [300. 最长递增子序列](https://leetcode-cn.com/problems/longest-increasing-subsequence/) #### 示例代码 以下是一个简单的动态规划问题示例——“不同路径”[^3]: ```python def uniquePaths(m, n): dp = [[1] * n for _ in range(m)] for i in range(1, m): for j in range(1, n): dp[i][j] = dp[i-1][j] + dp[i][j-1] return dp[-1][-1] # 测试用例 print(uniquePaths(3, 2)) # 输出:3 ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值