代码随想录——二叉树19.最大二叉树
1.代码随想录-逆波兰式、滑动窗口最大值2.代码随想录-栈与队列-有效的括号(括号匹配)3.代码随想录——栈与队列8-前K个高频元素4.二叉树的递归遍历和迭代遍历5.代码随想录——二叉树-11.完全二叉树的节点个数6.代码随想录——二叉树-12.平衡二叉树7.代码随想录——二叉树17-路径总和
8.代码随想录——二叉树19.最大二叉树
9.代码随想录——二叉树21、合并二叉树(附:递归算法复杂度分析)10.代码随想录——二叉树23、验证二叉搜索树11.代码随想录——25二叉搜索树的最小绝对值差(递归遍历如何记录前后两个指针)12.代码随想录——25.二叉搜索树中的众数13.代码随想录——26、二叉(搜索)树的最近公共祖先14.代码随想录——回溯8、组合总和II15.代码随想录——回溯9.分割回文串16.代码随想录——回溯19重新安排行程17.代码随想录——回溯 N皇后18.代码随想录——贪心8.跳跃游戏II19.代码随想录——贪心9.K次取反后最大化的数组和 && std::sort函数的第三个参数说明20.代码随想录——贪心13.分发糖果21.代码随想录——贪心算法:根据身高重建队列 & Vector原理22.代码随想录——贪心算法22单调递增的数字23.代码随想录——贪心23监控二叉树24.代码随想录——动态规划5.周总结25.代码随想录——动态规划9不同的二叉搜索树26.代码随想录——动态规划01背包27.代码随想录——动态规划13.分割等和子集28.代码随想录——动态规划14最后一块石头的重量II(01背包)29.动态规划——dp的含义归类(完全背包和01背包区别)30.动态规划——26单词拆分31.代码随想录——动态规划背包问题总结32.代码随想录——动态规划31打家劫舍III(树状DP)33.代码随想录——动态规划、股票问题34.代码随想录——单调栈35.回溯总结
递归
最容易想到,采用先序遍历。
1.遍历数组,找出当前区间的最大值;
2.使用该最大值作为根节点;
3.对数组的左半部分和右半部分递归调用构建最大二叉树。
这种方式是标准的 分治法,每次递归都需要遍历当前区间,找到最大值。因此,时间复杂度是 O(n^2),因为每一层递归都会遍历一遍数组,且递归的深度为 n。
一定要坚持循环不变量,这里的递归区间都选择左闭右开区间
代码
class Solution {
public:
//本题和从中序后续构造二叉树不同,本题每次递归只用使用一个数组, 所以只需要left和right
TreeNode* buildTree(vector<int>& nums,int left,int right){//[left,right)区间
//先序遍历 递归
if(left >= right)return nullptr;
//遍历找到最大值和索引
int maxNum = -1,maxId = 0;
for(int i = left;i<right;i++){
if(nums[i] > maxNum){
maxNum = nums[i];
maxId =i;
}
}
TreeNode* root = new TreeNode(maxNum);
root->left = buildTree(nums,left,maxId);
root->right = buildTree(nums,maxId+1,right);
return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return buildTree(nums,0,nums.size());
}
};
单调栈
单调栈是一个辅助数据结构,用来维护某些元素的顺序(例如,递增或递减顺序)。在这道题中,我们可以利用单调栈来帮助我们快速找到每个元素在构建最大二叉树时的 父子关系
为什么单调栈能够优化?
单调栈能优化这个问题的关键在于它能够快速找到每个元素的 最大值 以及该值在当前区间内的位置,而不需要每次都遍历整个区间。它通过维护一个单调栈来做到这一点,从而提高时间效率。时间复杂度O(N)。
步骤:
单调栈的维护:我们从左到右扫描数组,对于每个新元素 nums[i]:
- 如果栈顶的元素比 nums[i] 小,栈顶元素出栈,作为当前元素的左子树,直到栈顶元素比 nums[i] 大或栈为空。
- 如果栈顶元素比nums[i]大,当前元素入栈,作为栈顶元素的右子树
- 如果栈为空,当前元素直接入栈,更新要返回的root节点为当前元素节点(此时当前元素一定是局部的最大值)
代码
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
// return buildTree(nums,0,nums.size());
stack<TreeNode*> st;
TreeNode* root = nullptr;
for(int num:nums){
TreeNode* node = new TreeNode(num);
//1.如果栈非空,且栈顶值小于当前值,出栈作为左子树
while(!st.empty() && st.top()->val < num){
node->left = st.top();
st.pop();
}
//2.如果栈非空,且栈顶值大于当前值,入栈作为右子树
if(!st.empty()){
st.top()->right = node;
st.push(node);
}else{//3.栈为空,直接入栈;
root = node;
st.push(node);
}
}
return root;
}
合集:
代码随想录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现