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

leetcode算法刷题的第十七天

1.leetcode 235.二叉搜索树的最近公共祖先

题目链接

第一种解法:递归法

/*** 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* traversal(TreeNode* current,TreeNode* p,TreeNode* q){if(current==NULL) return NULL;if(current->val>p->val&&current->val>q->val){TreeNode* left=traversal(current->left,p,q);if(left!=NULL) return left;}if(current->val<p->val&&current->val<q->val){TreeNode* right=traversal(current->right,p,q);if(right!=NULL) return right;}return current;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {return traversal(root,p,q);}
};

因为二叉搜索树的性质,当两个节点的值的大小都比根节点小的话,那说明最近公共祖先肯定是在左子树中,反之就在右子树中。至于遍历的顺序,也是因为这个性质,所以不用考虑这个遍历顺序,前中后序遍历都可以。

第二种解法:迭代法

利用其有序性,迭代的方式还是比较简单的。

/*** 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* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {while(root){if(root->val>p->val&&root->val>q->val){//左root=root->left;}else if(root->val<p->val&&root->val<q->val){//右root=root->right;}else{return root;}}return NULL;}
};

思路总结:相比于二叉树的最近公共祖先,二叉搜索树的最近公共祖先还是更加简单的,究其原因就是二叉搜索树的特性,当然我们看到二叉搜索树的时候,脑子也要想到中序遍历,这样我们所组成的数组就是有序的,这样对我们的操作更加的方便。

2.leetcode 701.二叉搜索树中的插入操作

题目链接

第一种解法:递归法

/*** 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* insertIntoBST(TreeNode* root, int val) {if(root==NULL){TreeNode* node=new TreeNode(val);return node;}if(root->val>val){root->left=insertIntoBST(root->left,val);}if(root->val<val){root->right=insertIntoBST(root->right,val);}return root;}
};

第二种解法:迭代法

/*** 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* insertIntoBST(TreeNode* root, int val) {if(root==NULL){TreeNode* node=new TreeNode(val);return node;}TreeNode* current=root;TreeNode* parent=root;//这个很重要,需要记录上一个节点,否则无法赋值新节点while(current!=NULL){parent=current;if(current->val>val) current=current->left;else current=current->right;}TreeNode* node=new TreeNode(val);if(val<parent->val) parent->left=node;// 此时是用parent节点的进行赋值else parent->right=node;return root;}
};

思路总结:

首先在二叉搜索树中的插入操作,大家不用恐惧其重构搜索树,其实根本不用重构。

然后在递归中,我们重点讲了如何通过递归函数的返回值完成新加入节点和其父节点的赋值操作,并强调了搜索树的有序性

最后依然给出了迭代的方法,迭代的方法就需要记录当前遍历节点的父节点了,这个和没有返回值的递归函数实现的代码逻辑是一样的。

3.leetcode 450.删除二叉搜索树中的节点

题目链接

这道题还是比较有难度的,因为删除节点涉及到要重构树的结构,让这个数还是二叉搜索树。

第一种解法:递归法

/*** 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* deleteNode(TreeNode* root, int key) {// 第一种情况:没找到删除的节点,遍历到空节点直接返回了if(root==NULL) return NULL;if(root->val==key){// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点if(root->left==NULL&&root->right==NULL){delete root;return NULL;}// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点else if(root->left==NULL&&root->right!=NULL){auto retNode=root->right;delete root;return retNode;}// 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点else if(root->left!=NULL&&root->right==NULL){auto retNode=root->left;delete root;return retNode;}// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置// 并返回删除节点右孩子为新的根节点。else{TreeNode* current=root->right;// 找右子树最左面的节点while(current->left!=NULL){current=current->left;}current->left=root->left;// 把要删除的节点(root)左子树放在cur的左孩子的位置TreeNode* temp=root;// 把root节点保存一下,下面来删除root=root->right;// 返回旧root的右孩子作为新rootdelete temp; // 释放节点内存return root;}}if(root->val>key) root->left=deleteNode(root->left,key);//向左遍历if(root->val<key) root->right=deleteNode(root->right,key);//向右遍历return root;}
};

第二种解法:迭代法

删除节点的迭代法还是要复杂一点的。

/*** 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 {
private:// 将目标节点(删除节点)的左子树放到 目标节点的右子树的最左面节点的左孩子位置上// 并返回目标节点右孩子为新的根节点TreeNode* deleteOneNode(TreeNode* target) {if (target == nullptr) return target;if (target->right == nullptr) return target->left;TreeNode* cur = target->right;while (cur->left) {cur = cur->left;}cur->left = target->left;return target->right;}
public:TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr) return root;TreeNode* cur = root;TreeNode* pre = nullptr; // 记录cur的父节点,用来删除curwhile (cur) {if (cur->val == key) break;pre = cur;if (cur->val > key) cur = cur->left;else cur = cur->right;}if (pre == nullptr) { // 如果搜索树只有头结点return deleteOneNode(cur);}// pre 要知道是删左孩子还是右孩子if (pre->left && pre->left->val == key) {pre->left = deleteOneNode(cur);}if (pre->right && pre->right->val == key) {pre->right = deleteOneNode(cur);}return root;}
};

思路总结:这道题还是建议先好好学习一下递归法,虽然迭代法和递归法的思路是一致的,但是递归法的解法更好理解。

二叉搜索树添加节点只需要在叶子上添加就可以的,不涉及到结构的调整,而删除节点操作涉及到结构的调整。

这里我们依然使用递归函数的返回值来完成把节点从二叉树中移除的操作。

这里最关键的逻辑就是第五种情况(删除一个左右孩子都不为空的节点),这种情况一定要想清楚

而且就算想清楚了,对应的代码也未必可以写出来,所以这道题目既考察思维逻辑,也考察代码能力

迭代法其实不太容易写出来,所以如果是初学者的话,彻底掌握第一种递归写法就够了。

http://www.dtcms.com/a/350520.html

相关文章:

  • 房地产模式的运行逻辑与内在风险
  • Acrobat DC 中的条件格式化
  • 失眠——记录安东尼威廉饮食习惯的250天
  • 推三返一链动模式裂变图解
  • 用Python的Requests+BeautifulSoup爬取微博热搜榜及话题内容
  • SSM从入门到实战:3.1 SpringMVC框架概述与工作原理
  • 音视频学习(五十八):STAP-A模式
  • 编写Linux下usb设备驱动方法:probe函数中要完成的任务
  • 麦特轮巡线避障小车开发
  • IEEE子刊 | 注意缺陷多动障碍的功能连接模式:近红外机器学习研究
  • QML中的QtObject
  • QT新建文件或者项目解释:那些模板分别是什么意思?
  • 前端部署终极详细指南
  • 容器日志收集配置在云服务器环境中的集成方案
  • JWT用户认证后微服务间如何认证?(双向TLS(mTLS)、API网关、Refresh Token刷新Token)微服务间不传递用户认证Token
  • C-JSON接口的使用
  • 【什么是端到端模型】
  • 益莱储@PCIe技术大会
  • Bright Data 代理 + MCP :解决 Google 搜索反爬的完整方案
  • WPF 参数设置界面按模型字段自动生成设置界面
  • Docker:网络连接
  • python面试题目100个(更新中预计10天更完)
  • 深度学习(二):数据集定义、PyTorch 数据集定义与使用(分板块解析)
  • 决策树原理与 Sklearn 实战
  • 【动手学深度学习】7.1. 深度卷积神经网络(AlexNet)
  • 0825 http梳理作业
  • 【慕伏白】CTFHub 技能树学习笔记 -- Web 之信息泄露
  • Linux多线程[生产者消费者模型]
  • python项目中pyproject.toml是做什么用的
  • 【Canvas与标牌】维兰德汤谷公司logo