刷题记录2

文章目录

  • 刷题记录2
    • 1047.删除字符串中的所有相邻重复项
    • 150.逆波兰表达式求值
    • 239.滑动窗口最大值
    • 347.前k个高频元素
    • 144.二叉树前序遍历(145、94后序、中序)
    • 102.二叉树的层序遍历
    • 226.翻转二叉树
    • 101.对称二叉树
    • 104.二叉树的最大深度
    • 111.二叉树的最小深度
    • 222.完全二叉树的节点个数

刷题记录2

1047.删除字符串中的所有相邻重复项

class Solution {
public:string removeDuplicates(string s) {string res = "";for(char a : s){if(res.empty() || res.back() != a) res.push_back(a);else if(res.back() == a) res.pop_back();}return res;}
};

像这种消消乐类型的题目都是用到的栈这种数据结构来解决问题,而这里呢是将string来代替栈,就不需要用到stack容器,如果使用stack容器还需要将容器内的元素重新遍历赋值到string中,然后还需要一次reverse反转,如果直接使用string作为栈就节省了代码和时间。这里在解题的时候遇到了一个空间性能上的一个问题,就是我将res.push_back(a)改成了res = res+a这种写法会导致内存超限,并且耗时将近500ms。我就在像这是为什么呢?两个操作明明都是在字符串尾部添加字符a,为什么空间和时间性能就相差这么大呢?通过搜索得知:res = res+a这种操作是会重新生成一个string临时变量,先将原本的res拷贝到临时变量中再添加上a再返回给res,这个操作又是在循环当中,假如题目中给出的s十分长,那么就相当于是On^2的时间复杂度了,再加上每个循环开辟一个临时变量,所以空间消耗也十分大。对于res.push_back来说它仅仅只是在res的基础上在后面添加字符a,这样要比运算符+要节省空间和时间很多。所以在遇到对字符串进行添加或删除时最好用push_back和pop_back。其他相关函数front(), back(), append()。

150.逆波兰表达式求值

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> s;for(int i = 0; i < tokens.size(); i++){if(tokens[i] == "+"){int num1 = s.top();s.pop();s.top() += num1;}else if(tokens[i] == "-"){int num1 = s.top();s.pop();s.top() -= num1;}else if(tokens[i] == "*"){int num1 = s.top();s.pop();s.top() *= num1;}else if(tokens[i] == "/"){int num1 = s.top();s.pop();s.top() /= num1;}else s.push(stoi(tokens[i]));}return s.top();}
};

这一题其实只要读懂题目的意思就行了,然后按照题目给的要求编程就行了,关键是要明白这个题要用栈来写,看到提示:遇到数字则入栈,遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中,这里着重强调一下一个数字字符串转换数字的方法:int num = stoi(“12345”);但是呢,好像int num = "12345"也是能实现的,都记住吧,技多不压身。。。

239.滑动窗口最大值

class Solution {
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> ans;deque<int> dq;for(int i = 0; i < nums.size(); i++){//入while(!dq.empty() && nums[i] >= nums[dq.back()]) dq.pop_back();dq.push_back(i);//出if(i-dq.front() >= k) dq.pop_front();//记录数据if(i >= k-1) ans.push_back(nums[dq.front()]);}return ans;}
};

以前绝对遇到过这种题!我记得当时我单纯用for循环嵌套都写不出来着,现在至少能用for循环嵌套能够写出来了,当然如果暴力的话怎么可能解决力扣的困难题呢,果然不出意外的运行超时了。当然有提升是肯定的,加油!

这里用到的数据结构是单调队列,做这么多题下来好像确实没怎么写过队列的题目。这里用到的思想是维护一个单调的队列来记录nums[i]的值,这里题目求的是滑动窗口的最大值,那么我们就需要维护一个单调递减的一个队列,将最大的元素一直停留在队列的首位。首先是入队操作,循环判断队尾的元素是不是小于要插入进来的元素,如果尾元素小于要插入的元素的话就不断地将尾元素剔除,目的就在于使这个队列是递减的。然后就是出操作:插入元素后通过下标的循环不变量i-dq.front() >= k时就需要将首元素剔除掉。最后是记录数据操作,由于不同测试样例的窗口大小不同,所以前k个数据插入的时候是不需要记录数据的,所以当下标i=k-1的时候才开始记录结果。

347.前k个高频元素

144.二叉树前序遍历(145、94后序、中序)

递归法:

class Solution {
public:void preorder(TreeNode* root, vector<int>& res){if(root == nullptr) return;res.push_back(root->val);preorder(root->left, res);preorder(root->right, res);}vector<int> preorderTraversal(TreeNode* root) {vector<int> res;preorder(root, res);return res;}
};

中序和后序的递归方法还是很简单的,就是分别将res.push_back(root->val);放到两个递归函数的中间和后面,这样就分别达到了中序遍历和后序遍历的效果。

迭代法:

前序

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> s;vector<int> res;if(root == nullptr) return {};s.push(root);while(!s.empty()){TreeNode* temp = s.top();s.pop();res.push_back(temp->val);if(temp->right) s.push(temp->right);if(temp->left) s.push(temp->left);}return res;}
};

首先回顾前序遍历,它的递归方式是中左右。这样就不难写出前序遍历的递归写法。题目中的提升中给出要写出其迭代写法,最开始还是没有思路的,甚至想到的是用队列这种数据结构,但是经过脑袋一次思考之后回想起用队列的话是实现树的层序遍历,这并不能达到前中后序遍历的效果。看了一眼题解发现用的是栈,而且在使用栈的时候也是有需要注意的点:首先是入栈要判断树是否为空树,再就是入栈顺序,这里是右子树先入栈,左子树后入栈,由于栈是先入后出,所以是先右后左,还有就是入栈前需要对左右节点进行判空操作,如果为空那么就不能入栈,如果入栈了的话会导致空指针异常。

后序

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*> s;vector<int> res;if(root == nullptr) return {};s.push(root);while(!s.empty()){TreeNode* temp = s.top();res.push_back(temp->val);s.pop();if(temp->left) s.push(temp->left);if(temp->right) s.push(temp->right);}reverse(res.begin(), res.end());return res;}
};

最开始想借着前序遍历的写法来写后序遍历,结果还是卡住了,卡尔给出的方法也实在是妙啊,前序遍历是中左右,而后序遍历是左右中,它采用的方法就是在指针入栈方面进行了改动,先将左右指针入栈的顺序颠倒了一下,就使结果变成了中右左,然后将res数组进行翻转就变成了最后的左右中,我天,这是人能想出来的办法吗555,真的佩服!

中序

class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {stack<TreeNode*> s;vector<int> res;TreeNode* cur = root;while(!s.empty() || cur != nullptr){if(cur != nullptr){s.push(cur);cur = cur->left;}else{cur = s.top();s.pop();res.push_back(cur->val);cur = cur->right;}}return res;}
};

中序和其他两个差别还是很大的,主要难点在于用栈来模拟递归的逻辑这一点第一次来写确实有点难写,这方面还是有点薄弱,虽说考试不可能考迭代法写二叉树遍历、但这也是考试和以后面试的两手准备吧!

102.二叉树的层序遍历

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {deque<TreeNode*> dq;vector<vector<int>> res;if(root == nullptr) return {};dq.push_back(root);while(!dq.empty()){int n = dq.size();vector<int> temp;for(int i = 0; i < n; i++){TreeNode* tmp = dq.front();dq.pop_front();temp.push_back(tmp->val);if(tmp->left) dq.push_back(tmp->left);if(tmp->right) dq.push_back(tmp->right);}res.push_back(temp);}return res;}
};

这也是第二次做这道题了,唉又没做出来,还是忘得快啊,这才过了一个多月的题,就忘得一干二净了,当时在思考的时候还是想到的是以前自己的思路,就是没有回忆到以前题解的思路。这一题的层序遍历与其他不同点就在于每层的数据是一个一维数组,然后最后的结果是一个二维数组。其实感觉自己也是把题目想复杂化了,其实就是层多少个元素就将每层的元素传入到临时的一维数组中,多少个元素直接用dq.size()就能获取到。唉,给我最大的感觉就是还得回头看,重点的确不是在于多,还是在于你要掌握这个方法。

226.翻转二叉树

class Solution {
public:void reverse(TreeNode* root){if(root == nullptr) return;swap(root->left, root->right);if(root->left) reverse(root->left);if(root->right) reverse(root->right);}TreeNode* invertTree(TreeNode* root) {reverse(root);return root;}
};

最开始我想着能不能取巧只交换节点的值是否能够达到效果,答案是不能,不能被题干中的示例给迷惑了,可能出现问题的情况是一个节点可能只有左右子树中的一个,这样就不能够通过交换左右节点的值来达到交换的效果,会出现空指针异常的错误。所以这里只能够用交换指针来达到目的,最开始我也对交换完指针之后是否会对后续递归产生问题产生疑惑,其实是不会的,无论是左右节点哪个先递归,最终目的是让所有其左右节点指针互换就行,所以只需要关注遍历整个树,这样就能达到我们最后想要的效果。

101.对称二叉树

class Solution {
public:bool isSame(TreeNode* p, TreeNode* q){//这一行包含了很多条件://1、左空右非空返回false//2、左非空右空返回false//3、左右都空返回trueif(p == nullptr || q == nullptr) return p == q;//左右都非空bool outside = isSame(p->left, q->right);bool inside = isSame(p->right, q->left);bool val = p->val == q->val;return val && outside && inside;}bool isSymmetric(TreeNode* root) {return isSame(root->left, root->right);}
};

打开这一道题显示是1个月前做的题,现在一看,感觉跟新题没什么差别,唉还是没有思路。感觉前面跟灵神学做的算法题还是过于草率了,慢慢看出差别了,灵神讲题更注重于代码简洁和方法的灵活上面,这对于我们这种普通人来说接受起来只有那种昙花一现的效果,并不能将方法牢记于心,卡尔讲题确确实实落实在了干货上面,落在了基础上面,这才是真正的好讲师啊!

对于这一次提交的代码,我结合了灵神和卡尔的思路。首先对于递归退出的条件我只用一行解决了,但那一行代表的含义是丰富的,具体请看代码注释,再就是左右都非空的情况,这里就要用到后序遍历,为什么用后序遍历?卡尔给出的解释是:由于每一个节点都需要其孩子的真假信息才能判断当前节点的真假信息,需要将孩子的信息回溯到当前节点综合判断,所以用到的是后序遍历,解决二叉树问题无非就是四种遍历方式,但是具体采用哪一种一定要根据题意来采用,不同的遍历方式对于不同的题目产生的答案有可能不同,有时候一个题可以采用多种遍历方式,而有些题仅能采用某一种方式解题,这就是我之前刷题所遗漏的地方。最后解释一下val那一行,先进行的 == 运算,==运算的结果返回到val中,那一行也能写成bool val = p->val == q->val ? 1 : 0;还有就是return返回的值需要val、outside和inside综合判断真价值

这一道题给了我很大的感触吧,刷题确实不能图快,有时回过头来做的题其实又是一个新题。。。不能一个劲的追求简洁,扎实才是王道啊!

104.二叉树的最大深度

class Solution {
public:int func(TreeNode* root){if(root == nullptr) return 0;int leftNum = func(root->left);int rightNum = func(root->right);return max(leftNum, rightNum)+1;}int maxDepth(TreeNode* root) {return func(root);}
};

这里给出二叉树的两个定义:深度:指节点到根节点的距离,根节点的深度为1;高度:节点到叶子节点的距离,叶子节点的高度为1。所以求深度最好是用前序遍历采用迭代方法比较好,但是写的话会比较麻烦,这里采用的是后序遍历,为什么会是后序遍历呢?题干求的是最大深度,那么是不是可以理解成求二叉树的最大高度呢?求最大高度也就是求根节点的高度,这样由叶子节点一步一步往上传递就用到的是后序遍历。

111.二叉树的最小深度

class Solution {
public:int minDepth(TreeNode* root) {if(root == nullptr) return 0;int leftnum = minDepth(root->left);int rightnum = minDepth(root->right);if(root->left == nullptr && root->right != nullptr) return 1+rightnum;else if(root->right == nullptr && root->left != nullptr) return 1+leftnum;else return min(leftnum, rightnum)+1;}
};

整体上与前面一道题是相同的解法,也是用到的后序遍历的方法,但是再返回值上有一点不同,需要对二叉树的各种情况进行讨论,先是左空右不空的情况—>返回根节点右子树的最小深度+1、右空左不空与前面上一个情况相反,最后是都不空的情况,直接返回根节点的最小深度。

结合前面的对称二叉树的题目,我发现其实在一般情况你写完提交后不能通过全部样例时就需要考虑二叉树的几个特殊情况:左空右不空、左不空右空、左右都不空、左右都空。

222.完全二叉树的节点个数

方法一:

class Solution {
public:int countNodes(TreeNode* root) {if(root == nullptr) return 0;return countNodes(root->left) + countNodes(root->right)+1;}
};

方法二:

class Solution {
public:int countNodes(TreeNode* root) {if(root == nullptr) return 0;TreeNode* p_left = root->left, *p_right = root->right;int leftDepth = 1, rightDepth = 1;while(p_left){leftDepth++;p_left = p_left->left;}while(p_right){rightDepth++;p_right = p_right->right;}if(leftDepth == rightDepth) return pow(2, leftDepth)-1;int leftNum = countNodes(root->left);int rightNum = countNodes(root->right);return leftNum+rightNum+1;}
};

方法一用的普通的后序遍历求完全二叉树的个数,因为遍历了整棵树所以时间复杂度是On的,而方法二用到了题干给出的完全二叉树的性质,利用完全二叉树的性质使时间复杂度降低了。具体的逻辑:在递归到每个节点的时候写一段代码来判断以当前节点为根节点的二叉树是否为完全二叉树,如果是,直接将2^深度-1返回给上一级,如果不是那么就继续后序遍历该树。如何判断一个子树是否为完全二叉树?—>由于题目中给出的树一定是完全二叉树,那么我们只需要从当前节点定义两个指针,分别一直往左迭代和往右迭代直到指为空,迭代的过程中用两个int型的变量记录各自的深度,最后判断两个深度是否相等,如果相等那么这个子树就是完全二叉树,反之则不是。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/9114.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python sqlite3库 实现 数据库基础及应用 输入地点,可输出该地点的爱国主义教育基地名称和批次的查询结果。

目录 【第11次课】实验十数据库基础及应用1-查询 要求: 提示: 运行结果&#xff1a; 【第11次课】实验十数据库基础及应用1-查询 声明&#xff1a;著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 1.简答题 数据库文件Edu_Base.db&#…

国内唯一!阿里云荣膺MongoDB“2024年度DBaaS认证合作伙伴奖”

近日&#xff0c;在MongoDB用户大会纽约站上&#xff0c;阿里云荣膺MongoDB“2024年度DBaaS认证合作伙伴奖”。这是阿里云连续第五年斩获MongoDB合作伙伴奖项&#xff0c;也是唯一获此殊荣的中国云厂商。 MongoDB是当今全球最受欢迎的非关系型数据库之一。凭借灵活的模式和丰富…

day10-16:Spring Security

Spring Security安全控制 1、介绍Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。 2、功能Authentication 认证&#xff0c;就是用户登录Authorization 授权&#xff0c;判断用户拥有什么权限&#xff0c;可以访问什么资源…

Unity 修复Sentinel key not found (h0007)错误

这个问题是第二次遇到了&#xff0c;上次稀里糊涂的解决了&#xff0c;也没当回事&#xff0c;这次又跑出来了&#xff0c;网上找的教程大部分都是出自一个人。 1.删除这个路径下的文件 C:\ProgramData\SafeNet Sentinel&#xff0c;注意ProgramData好像是隐藏文件 2.在Windows…

Redis(安装及配置)

1.什么是redis Redis 全称 Remote Dictionary Server&#xff08;即远程字典服务&#xff09;&#xff0c;它是一个基于内存实现的键值型非关系&#xff08;NoSQL&#xff09;数据库&#xff0c;由意大利人 Salvatore Sanfilippo 使用 C 语言编写。 2.优势 性能极高&#xff…

如何进行资产梳理

前言 为什么要进行资产梳理&#xff1f; 资产梳理方式一: 一、安全防护设备资产 二、对外开放服务项目资产 三、项目外包业务流程资产 资产梳理方式二: 一、业务资源梳理 二、设备资产梳理 三、第三方的服务信息梳理 风险梳理 风险有哪些&#xff1f; 一,账号权限风…

【VTKExamples::Rendering】第一期 TestAmbientSpheres(环境照明系数)

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例TestAmbientShperes,介绍环境照明系数对Actor颜色的影响,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动…

《ESP8266通信指南》14-连接WIFI(基于Lua)

往期 《ESP8266通信指南》13-Lua 简单入门&#xff08;打印数据&#xff09;-CSDN博客 《ESP8266通信指南》12-Lua 固件烧录-CSDN博客 《ESP8266通信指南》11-Lua开发环境配置-CSDN博客 《ESP8266通信指南》10-MQTT通信&#xff08;Arduino开发&#xff09;-CSDN博客 《ES…

Python中对象数据的持久化操作

含义&#xff1a; 对象数据的持久化操作指的是将Python程序中的对象保存到某种形式的持久化存储介质&#xff08;如文件、数据库&#xff09;中&#xff0c;以便在程序重新运行或在其他程序中使用时能够重新加载这些对象。持久化操作可以确保数据在程序关闭后不会丢失&#xff…

谷歌明年6月关闭 Google Fit 运动记录API,要求开发者迁移至Android Health平台 | 最新快讯

5 月 6 日消息&#xff0c;谷歌近日发布官方新闻稿&#xff0c;宣布将在明年 6 月使用 Android Health 平台取代 Google Fit 运动记录 API&#xff0c;开发人员应当尽早启动迁移计划。 谷歌自 2022 年起逐渐扩大对 Android Health 平台的投资&#xff0c;旨在减少平台碎片化&am…

Java17 --- SpringCloud之Zipkin链路追踪

目录 一、下载zipkin及运行 二、在父工程中引入pom依赖 三、在子工程8001引入相关pom依赖 3.1、修改yml配置文件 3.2、测试代码 四、在子工程80引入相关pom依赖 4.1、修改yml配置文件 4.2、测试代码 五、测试结果 一、下载zipkin及运行 运行控制台访问地址&#xff1…

Linux学习笔记1---Windows上运行Linux

在正点原子的教程中学习linux需要安装虚拟机或者在电脑上安装一个Ubuntu系统&#xff0c;但个人觉得太麻烦了&#xff0c;现在linux之父加入了微软&#xff0c;因此在Windows上也可以运行linux 了。具体方法如下&#xff1a; 一、 在Windows上的设置 在window的搜索框内&#…

【Java】还不会数组?一文万字全搞定

前言&#xff1a;前面两章我们详细讲解了Java基本程序设计结构中的基本知识&#xff0c;&#xff0c;包括&#xff1a;一个简单的Java应用&#xff0c;注释&#xff0c;数据类型&#xff0c;变量与常量&#xff0c;运算符&#xff0c;字符串&#xff0c;输入输出&#xff0c;控…

代码随想录算法训练营第二十三天|617.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

617.二叉搜索树的最小绝对差 文档讲解:代码随想录 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 遇到二叉搜索树&#xff0c;就要知道这棵树在中序遍历的情况下是一个升序的遍历。 这道题目的难点就是如何使用双指针遍历二叉树&#xff0c;一个指向中序遍历…

三条命令快速配置Hugging Face

大家好啊&#xff0c;我是董董灿。 本文给出一个配置Hugging Face的方法&#xff0c;让你在国内可快速从Hugging Face上下在模型和各种文件。 1. 什么是 Hugging Face Hugging Face 本身是一家科技公司&#xff0c;专注于自然语言处理&#xff08;NLP&#xff09;和机器学习…

写爬虫代码抓取Asterank中小行星数据

2024年5月4日 问题来源 解决方案 回顾2023年7月14日自己写的爬虫代码 import requests import re import pandas as pd texts[] def getData(page):#每页评论的网址urlhttps://item.jd.com/51963318622.html#comment#添加headers&#xff0c;伪装成浏览器headers{User-Agent:…

即插即用 | YOLOv8热力图可视化方法详解,揭秘AI如何「看」世界!【附完整源码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

常见的前端框架

常用的前端框架有以下几种&#xff1a; 模型 React&#xff1a;由Facebook开发的一款前端框架&#xff0c;采用虚拟DOM的概念&#xff0c;可高效地更新页面。Vue.js&#xff1a;一款轻量级的前端框架&#xff0c;易学易用&#xff0c;支持组件化开发和双向数据绑定。AngularJ…

接口框架项目实战-pytest(四)请求封装接口关联

把所有的请求方法集中到一个地方 目的&#xff1a;利于后期维护和加入日志 异常处理 等 目的&#xff1a;框架封装好之后&#xff0c;功能测试不需要写代码&#xff0c;也能执行自动化测试 config.yml base:base_php_url: http://47.107.116.139base_wx_url: https://api.weix…

vivado 低级别 SVF JTAG 命令、多链 SVF 操作

多链 SVF 操作 以下示例显示了如何在 SVF 链上处理操作。 每个链中连接有 2 个器件 &#xff1a; xcku11 和 xcku9 。配置存储器连接到链中的第 2 个器件 (xcku9) 。为访问此配置存储器 &#xff0c; SVF 会使用 HIR 、 HDR 、 TIR 和 TDR 命令来生成命令。为刷写此…