当前位置: 首页 > news >正文

leetcode每日一题41

99. 恢复二叉搜索树

中序遍历树,找到逆序的两个数,交换
有两种情况
如果是像示例1一样的,中序遍历后是3,2,1
是连续的两个逆序,那么交换第一,第三个数
如果是像示例2一样,中序遍历后是1,3,4,2
是一个逆序,那么交换这两个数即可

class Solution {
public:vector<int> vec;void traversal(TreeNode* root){if(root==nullptr)return;traversal(root->left);vec.push_back(root->val);traversal(root->right);}void recover(TreeNode* root,int count,int x,int y){if(root!=nullptr){if(root->val==x||root->val==y){if(root->val==x)root->val=y;else root->val=x;if(--count==0)return;}}if (root->left != nullptr) {recover(root->left, count, x, y);}if (root->right != nullptr) {recover(root->right, count, x, y);}return;}int index1=-1,index2=-1;void recoverTree(TreeNode* root) {traversal(root);for(int i=1;i<vec.size();i++){if(vec[i-1]>vec[i]){index2=i;if(index1==-1)index1=i-1;else break;}}cout<<index1<<index2<<endl;recover(root,2,vec[index1],vec[index2]);}
};

102.二叉树的层序遍历

模板,记住就行了
借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,
用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
用result保存层序遍历的结果
用vec保存一层的结果
用que保存该层的子节点

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if(root!=nullptr)que.push(root);vector<vector<int>> result;while(!que.empty()){int size=que.size();vector<int> vec;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}result.push_back(vec);}return result;}
};

103.二叉树的锯齿形层序遍历

在奇数次遍历次数时,reverse一下该层vec就行了

class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {queue<TreeNode*> que;int level=0;if(root!=nullptr)que.push(root);vector<vector<int>> result;while(!que.empty()){int size=que.size();vector<int> vec;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();vec.push_back(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}if(level%2)reverse(vec.begin(),vec.end());level++;result.push_back(vec);}return result;}
};

或者使用双端队列deque保存该层的节点

class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {queue<TreeNode*> que;if(root!=nullptr)que.push(root);vector<vector<int>> result;bool isOrderLeft = true;while(!que.empty()){int size=que.size();deque<int> level;for(int i=0;i<size;i++){TreeNode* node=que.front();que.pop();if(isOrderLeft)level.push_back(node->val);else level.push_front(node->val);if(node->left) que.push(node->left);if(node->right) que.push(node->right);}isOrderLeft=!isOrderLeft;result.push_back(vector<int>{level.begin(), level.end()});}return result;}
};

105. 从前序与中序遍历序列构造二叉树

用前序遍历的节点分割中序遍历序列
将中序遍历分为左右子树
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取前序数组第一个元素作为节点元素。
第三步:找到前序数组第一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,⼀定是先
切中序数组)
第五步:切割前序数组,切成前序左数组和前序右数组
第六步:递归处理左区间和右区间
模板:

TreeNode* traversal (vector& preorder, vector& inorder) {
// 第一步
if (preorder.size() == 0) return NULL;
// 第二步:前序遍历数组第一个元素,就是当前的中间节点
int rootValue = preorder[preorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (preorder.size() == 1) return root;
// 第三步:找切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size();
delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 第四步:切割中序数组,得到 中序左数组和中序右数组
// 第五步:切割前序数组,得到前序左数组和前序右数组
// 第六步
root->left = traversal(前序左数组, 中序左数组);
root->right = traversal(前序右数组, 中序右数组);
return root;
}

此时应该注意确定切割的标准,是左闭右开,还有左开又闭,还是左闭又闭,这个就是不变量,要在递归中保持这个不变量。

class Solution {
public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {// 第一步if (preorder.size() == 0) return NULL;// 第二步:前序遍历数组第一个元素,就是当前的中间节点int rootValue = preorder[0];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (preorder.size() == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组vector<int> leftInorder(inorder.begin(), inorder.begin() +
delimiterIndex);vector<int> rightInorder(inorder.begin() + delimiterIndex + 1,
inorder.end() );// 第五步:切割前序数组,得到前序左数组和前序右数组vector<int>::iterator it = preorder.begin();preorder.erase(it);vector<int> leftPreorder(preorder.begin(), preorder.begin()
+ leftInorder.size());vector<int> rightPreorder(preorder.begin() +
leftInorder.size(), preorder.end());// 第六步root->left = buildTree(leftPreorder, leftInorder);root->right = buildTree(rightPreorder, rightInorder);return root;}
};

这个代码性能并不好,因为代码里每层递归都定义了新的vector,既耗时又耗空间
可以用索引的方式重新写这个代码

class Solution {
public:TreeNode* traversal(vector<int>& preorder,int preorderBegin,int preorderEnd, vector<int>& inorder,int inorderBegin,int inorderEnd){// 第一步if (preorderBegin >= preorderEnd) return NULL;// 第二步:前序遍历数组第一个元素,就是当前的中间节点int rootValue = preorder[preorderBegin];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (preorderEnd - preorderBegin == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组int leftInorderBegin = inorderBegin;int leftInorderEnd = delimiterIndex;int rightInorderBegin = delimiterIndex + 1;int rightInorderEnd = inorderEnd;// 第五步:切割前序数组,得到前序左数组和前序右数组int leftPreorderBegin = preorderBegin+1;int leftPreorderEnd = preorderBegin + 1 + delimiterIndex -
inorderBegin;int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex -
inorderBegin);int rightPreorderEnd = preorderEnd;// 第六步root->left = traversal(preorder,leftPreorderBegin,leftPreorderEnd, inorder,leftInorderBegin,leftInorderEnd);root->right = traversal(preorder,rightPreorderBegin,rightPreorderEnd, inorder,rightInorderBegin,rightInorderEnd);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {if (preorder.size() == 0) return NULL;TreeNode* node=traversal(preorder,0,preorder.size(),inorder,0,inorder.size());return node;}
};

106.从中序与后序遍历序列构造二叉树

和上道题类似,用后序的最后一个节点分割中序序列

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:TreeNode* traversal(vector<int>& inorder,int inorderBegin,int inorderEnd,vector<int>& postorder,int postorderBegin,int postorderEnd){// 第一步if (postorderBegin >= postorderEnd) return NULL;// 第二步:后序遍历数组最后一个元素,就是当前的中间节点int rootValue = postorder[postorderEnd-1];TreeNode* root = new TreeNode(rootValue);// 叶子节点if (postorderEnd - postorderBegin == 1) return root;// 第三步:找切割点int delimiterIndex;for (delimiterIndex = 0; delimiterIndex < inorder.size();delimiterIndex++) {if (inorder[delimiterIndex] == rootValue) break;}// 第四步:切割中序数组,得到中序左数组和中序右数组int leftInorderBegin = inorderBegin;int leftInorderEnd = delimiterIndex;int rightInorderBegin = delimiterIndex + 1;int rightInorderEnd = inorderEnd;// 第五步:切割后序数组,得到后序左数组和后序右数组int leftPostorderBegin = postorderBegin;int leftPostorderEnd = postorderBegin + delimiterIndex -
inorderBegin;int rightPostorderBegin = postorderBegin + (delimiterIndex -
inorderBegin);int rightPostorderEnd = postorderEnd-1;// 第六步root->left = traversal(inorder,leftInorderBegin,leftInorderEnd, postorder,leftPostorderBegin,leftPostorderEnd);root->right = traversal(inorder,rightInorderBegin,rightInorderEnd, postorder,rightPostorderBegin,rightPostorderEnd);return root;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {if(inorder.size()==0)return NULL;TreeNode* node = traversal(inorder,0,inorder.size(),postorder,0,postorder.size());return node;}
};

相关文章:

  • C语言——格式说明符前面加修饰符
  • Python算法例33 删除数字
  • 陈述式资源管理(2)
  • 动画墙纸:将视频、网页、游戏、模拟器变成windows墙纸——Lively Wallpaper
  • 阿里云2核2G3M服务器上传速度多少?下载速度快吗?
  • 编程语言的进化:智能化与多样化的未来
  • 机器学习之主成分分析(Principal Component Analysis,PCA)案例解析附代码
  • 深度理解Flutter:有状态Widget与无状态Widget的详细对比
  • 华为ipsec双冗余配置案例
  • 为什么游戏服务端用开发效率低的C++来写,其他语言无法胜任吗?
  • Go语言程序设计-第5章--函数
  • 【Swagger】常用注解的使用、SpringBoot的整合及生产环境下屏蔽Swagger
  • [每周一更]-(第43期):Golang版本的升级历程
  • linux安装anaconda
  • 自定义html5中日期选取器的样式
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • canvas 高仿 Apple Watch 表盘
  • es6要点
  • github指令
  • laravel with 查询列表限制条数
  • Logstash 参考指南(目录)
  • python docx文档转html页面
  • Python实现BT种子转化为磁力链接【实战】
  • vue 配置sass、scss全局变量
  • zookeeper系列(七)实战分布式命名服务
  • 多线程事务回滚
  • 关于 Cirru Editor 存储格式
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 力扣(LeetCode)21
  • 目录与文件属性:编写ls
  • 前端临床手札——文件上传
  • 我有几个粽子,和一个故事
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (一)kafka实战——kafka源码编译启动
  • (转)LINQ之路
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .net MVC中使用angularJs刷新页面数据列表
  • .net与java建立WebService再互相调用
  • /etc/motd and /etc/issue
  • :=
  • @synthesize和@dynamic分别有什么作用?
  • [2016.7.Test1] T1 三进制异或
  • [20170705]diff比较执行结果的内容.txt
  • [COGS 622] [NOIP2011] 玛雅游戏 模拟
  • [IDF]摩斯密码
  • [JavaWeb玩耍日记]Maven的安装与使用
  • [LeetCode] NO. 387 First Unique Character in a String
  • [Linux]----文件操作(复习C语言+文件描述符)