- 博客(91)
- 收藏
- 关注
原创 3508 设计路由器
三属性的组合保持唯一、不能重复,可以想到利用Map进行快速查找,但由于三个属性共同组成一个单元,使用哪个作为Key都不能快速定位。转而考虑利用Set进行查找,其存储的元素为三个属性的集合,即。是仅提供简单的push、pop、front、back接口,不支持迭代器遍历,适用于FIFO的简单任务;区间内的的元素个数,可以分别写两个函数找到开头和结尾的元素位置,计算二者间的距离即可。1. 数据结构的使用(queue、deque、set、map、tuple),n为元素的位置,从0开始。队列有两种结构可以选择,
2025-04-14 00:14:00
548
原创 437 路径总和III
的方式,进行快速计算。正常来说计算区间的前缀和需要遍历所有的元素累加,前缀和而是利用两个前缀和的差来计算。这道题的诉求可以拆分成两部分:1 找到所有可能的路径;2 快速计算路径的和。是已知的,要找的区间开始节点的前缀和是可以计算 =由于题目要求路径方向是向下的,因而可以采用。的遍历方式,遍历所有的路径。对于这种累加和的问题,可以适用。,因而可以通过map快速查找。是已知的,当前点的前缀和。
2024-12-26 22:40:28
380
原创 114 二叉树展开为链表
题目中已经明确,要用先序遍历的顺序展开,那么就需要按照“中-左-右”的顺序遍历二叉树,剩下的问题在于如何在遍历过程中完成链表指针的更新。由于“右子节点”需要链接到左子树最后一个节点之后,所以需要额外的指针。,并对左子树展开,展开完成后,将原右半部分添加到当前遍历的末尾。记录已展开链表的末尾。由于链表按照前序遍历的方式展开的,所以。,都需要对链表进行展开,具体将左子树移动到。
2024-12-16 23:57:01
170
原创 199 二叉树的右视图
dfs:对于二叉树而言,有前序、中序、后序这三种遍历顺序。为了看到树的右视图,可以选取中序遍历的方式,保证同一深度下左节点比右节点先访问,随着遍历不断更新每一层深度的节点值,右边的节点会不断覆盖已记录的左边节点值,等遍历完成时,记录即为最右侧的节点值。这道题需要遍历二叉树才能看到全部的右节点,而树的遍历又可以分为两种,深度优先(dfs)和广度优先(bfs);相应的,这道题的解法也可以从这两个方面入手。bfs:按照层进行遍历,一次能够看到同一层所有的节点。对于每一层,不断记录最右边的非空节点值即可。
2024-12-16 22:46:29
185
原创 146 LRU缓存
的优先级在O(1)内提高呢?首先,这个数据结构要是有序的,且它任意元素的删除和插入要在O(1)复杂度内完成。因此排除数组、队列、堆栈等,剩下链表作为一个不错的选择。现在,我们可以通过map快速定义到,待更新元素的位置。但要将链表中的元素删除,需要知道上一个节点才行,因此我们的链表不能是单向的,而是双向的。代码实现中,记得将双向链表元素删除、插入封装成函数,可以使代码更精简一些。如何选择合适的数据结构,将访问过的<可以利用Map,实现O(1)内<的形式就可以解决这道题了。要有O(1)时间复杂度。
2024-12-08 23:39:00
557
原创 148 排序链表
时间复杂度内解决问题,满足这个条件的常用排序算法有:快速排序(Quick Sort)、归并排序(Merge Sort)和堆排序(Heap Sort)。为空之外,链表内只有一个元素的情况也要返回,不然会陷入死循环。为空的情况,返回时也要注意返回。,快速找到链表中间的节点;使用自定义节点做一个伪。递归的终止条件,除了。
2024-12-08 23:04:19
609
原创 19 删除链表的倒数第N个结点
题目要求删除倒数第N个结点,并且返回头结点,就很适合利用递归的方法解决。递归既有前向的过程也有逆向的过程,本题中只需利用其逆向过程,找到倒数第N个结点,并返回该节点下一个节点的地址,即可完成删除。返回的节点地址应作为上一个节点。
2024-10-30 14:12:01
185
原创 2 两数相加
这道题可以用模拟很直观的解决,模式加法的计算过程,只不过套了一层链表的外衣。题目给出的数字在链表中是按照。排列的,即链表头节点的值代表相加数字的个位,这样只需要从链表头开始计算加法即可得到最终的结果。不为0,需要进位,需要额外在末尾添加一个节点。需要注意的是,最后遍历完两个链表之后,如果。
2024-10-23 23:43:05
339
原创 142 环形链表II
判断链表是否有环,当快慢指针相等时,链表中存在环。但环形链表II在其基础上,额外需要找到环的第一个节点,可以在快慢指针相遇的基础上,进一步分析。此时,如果使用两个指针分别从表头和相遇点开始移动,则这两个指针会相遇于环开始的节点,此时返回结果即可。如果链表存在环,则快慢指针相遇于环上一点(如下图),将链表拆分成。
2024-10-21 22:48:23
902
原创 240 搜索二维矩阵 II
可以向右、向下扩展元素都是升序,但选择哪个方向是不明确的,很容易陷入局部最优而找到不到全局最优解。所以需要改变查找的起始位置,使一个方向为升序,而另一个为降序,比如右上角,向下为升序而向左为降序。解这道题最重要的是如何利用从左到右、从上到下为升序的性质,快速找到目标元素。时,向下移动,不断逼近目标,且遍历路径不会重复,时间复杂度为。如果从左上角开始查找,如果当前。
2024-10-03 23:38:29
542
原创 48 旋转图像
正方形矩阵类似洋葱,可以由不同大小的正方形数字分层组合而成,而旋转后的元素只在所在的那一层中进行位置变换,且四次变换后可回到原位置,若将元素四次变换经过的位置找出来,把元素按照旋转顺序进行一次移动即可完成旋转。将这四个位置上的元素按顺序移动即可完成旋转,正方形一条边上所有的元素旋转完毕后,进入下一层。模拟的关键是找到旋转的内在规律,即旋转前后的位置坐标的变化规律。我们把一层正方形提取出来看,定义正方形左上角的坐标为。时,可以认为矩阵已经旋转完成。,经过第二次旋转得到。
2024-09-27 22:28:48
290
原创 54 螺旋矩阵
这道题可以直接用模拟解决,顺时针螺旋可以分解为依次沿“右-下-左-上”四个方向的移动,每次碰到“边界”时改变方向,边界是不可到达或已经到达过的地方,会随着指针移动不断收缩。
2024-09-24 22:02:39
219
原创 73 矩阵置零
需要利用原输入矩阵的空间,记录含有0的行号、列号。至于第一行是否含有0元素,可以使用第一列的第一个元素记录,第一列本身是否含有0,可以使用额外的。记录是否含0的过程,可以按照任意顺序开展,但更新矩阵0元素时,需注意最后处理第一行、第一列的元素,不然会影响其他矩阵元素记录的信息。的矩阵,一次遍历把含有0元素的行号、列号记录下来,然后再一次遍历把对应的行、列元素值更新为0,随后输出。原地算法,指除原有输入资料所占空间外,使用额外空间尽可能少(常数空间)的算法。,但其实可以进一步优化,使空间复杂度变为。
2024-09-22 18:11:48
438
原创 238 除自身以外数组的乘积
时间内解决,但是不能使用除法。仅使用乘法的话,看上去很难在一次遍历中得出想要的结果,但是没关系,一次遍历不行的话那就试试两次、三次,重要的是分析在一次遍历中能干些什么。一模一样,只不过是从后往前累乘的“后缀积”,这样经过两次遍历就可以凑全。因此,可以记录一个"前缀积"同样的情况存在于每一个。
2024-09-22 16:01:17
291
原创 189 轮转数组
刚好数组的前半部分、和后半部分分别翻转就可以变成轮转后的结果,因此只需要进行三次翻转即可完成。由于,末尾元素向前移动,会导致其他所有元素位置的改变,时间复杂度高;但如果换个角度,k次轮转,也可以看做。此外,轮转后的数组,后面的元素在前,前面的元素在后,将数组翻转过来是符合这个规律的。首先要理解轮转的含义,轮转 = 将数组末尾元素移动至首位。由此可知,有效的轮转数需要对数组长度取余,即。时,数组元素的顺序又恢复成初始状态,下一次轮转又与。个元素按顺序添加至数组中,操作后的数组取。,观察翻转后的数组是。
2024-09-20 22:48:39
489
原创 56 合并区间
排序之后,区间的扩展方向只能是从左向右,因此只需要比较当前区间和上一个合并后的区间是否重叠即可,只要当前区间的左边界在上一个合并后区间的右边, 就不会重叠,从当前区间开始继续进行后面的合并,这样一次遍历就能找到所有的区间。这道题乍一看很复杂,对于任意两个区间判断是否重叠就有四种可能,而且之前两个不重叠的区间可能会因为新的合并而变得重叠,不好处理。但是一旦想到可以给这些区间排序,问题就变得简单了。函数就能完成快速排序,时间复杂度。
2024-09-20 00:21:48
338
原创 53 最大子数组和
dp则是站在数组每一个元素的角度,找到当前元素与上一元素之间的关系,逐步递推,从局部最优推出全局最优,有点类似数学归纳法。这道题,没想到这么快就能用上,这里只不过把找和为K的子数组变成了和最大的子数组。前缀和和dp两种方法写出的代码看起来差不多,但二者的思想还是差很多的。观察两种方法,前缀和是从子数组的维度取考虑问题的,更直观协一些;在遍历过程中不断记录子数组和的最大值输出即可。,在过程中同时记录最大值即可。开始构建新的子数组,此时和为。在目标子数组中,此时和为。为结尾的子数组和最大为。
2024-09-17 22:48:18
620
原创 560 和为k的子数组
一开始看到连续非空序列,会想到是不是可以用双指针表示一个区间,然后通过一次遍历找出所有可能的区间,但看到元素的取值区间就知道行不通,这个方法仅适用于数组元素大于等于0的情况。若数字是负数,随着区间长度的增加,其和的值不一定会增加,因而只能把所有的区间遍历一遍去找。,而在一次遍历过程中,map只能存储当前位置之前的累加和,所以一举两得,只用一次遍历即可解决。这种类似两数之和的问题了,妙啊。,将连续序列的和,转化成两个序列和的值之差(感觉有点dp的影子)。区间内所有元素的和,因此。
2024-09-15 18:20:27
310
原创 438 找到字符串中所有字母异位词
仅包含小写字母,且异位词不关心字符的顺序,可以使用长度为26的数组,通过记录26个字母的个数来比较,减少时间复杂度。这个题目解法没什么特别的,遍历所有子串,比较与目标字符串是否满足异位词即可。唯一需要注意的是,提示。
2024-09-14 19:31:40
279
原创 3 无重复字符的最长子串
遍历过程中不断记录左右边界距离的最大值,最后返回输出即可。分别记录片段的左边界和右边界。的元素是否已存在:若存在,需要移动。首先要理解“子串”,是输入字符串。快速查找当前片段内的元素。从0~字符串长度,每次检查。
2024-09-12 23:14:26
183
原创 15 三数之和
需要换一种角度,可以从重复的三元组出发去想一想。给不同重复的三元组创立一种相同编码方式,可以通过从小到大排序来完成。其实也可以试着反过来想一想,先把数组排序,然后再从中找三元组怎么样呢?但是即便如此找到的三元组仍可能重复,还得有一步去重的操作。这样算下来,空间复杂度还是比较高的,且代码实现起来比较麻烦。若三数之和为0,那么只要知道其中的两个,就可以知道第三个数的值。若想在有序数组去除重复的三元组,仅需要在遍历。要找到所有和为0的三元组,使用暴力去解的话时间复杂度为。的值,需要借助有序数组递增的性质。
2024-09-11 00:02:37
925
原创 11 盛最多水的容器
由于直线的高度排列是随机的,不好控制,因此我们可以先从容器的长度入手。给定数组后,容器最大的长度 = 数组的长度。选择长度最大的容器,其容量不一定是最大的,但是可以通过不断收缩边界,从容器高度这一维度中寻找容量更大的可能性。边界可以从左边收缩,也可以从右边伸缩,所以可以借助。就还存在收缩的空间,由于容器的高度由高度较小的直线决定,因此每次收缩就选择两条边界中长度更小的那一个。在收缩的过程中,不断计算当前容器的容量,并记录一个最大值最后输出即可。(两条直线长度的最小值)。容器的盛水量由两个因素决定,一个是。
2024-09-04 23:28:20
246
原创 128 最长连续序列
最理想的情况是同样的序列仅遍历一次,一次遍历完所有序列中的元素,可以通过从序列的起点开始遍历解决。这样问题就变为如何识别序列的起点,这就很简单了,对于当前元素。数据结构,对数组元素去重,进一步优化运行时间。,那么若已知序列起点,目标值递增向后遍历,借助哈希表检查目标值是否存在,可以在。但是若从数组每一个元素开始,遍历查找序列,时间复杂度还是会达到。需要考虑到数组中可能存在重复元素,可以通过借助。是否在数组中,即可判断。
2024-08-29 23:22:46
422
原创 49 字母异位词分组
可以借助Map,来存储排列不同的异位词。Key为字母的升序排列,Value为不同异位词的数组。题目要求将字母异位词组合在一起,那么需要用一种方式,来该概括不同异位词。这些异位词的共性就是。,那么就可以使用一种统一的排列方式将其概括,比如升序排序。注意:字符串在C++中与数组或其他数据结构一样,可以用。
2024-08-23 00:01:27
298
原创 136 只出现一次的数字
这道题正是利用了自反性的特点,由于只有一个元素出现一次,其余全部出现两次,只要将他们全部异或,出现两次的元素异或结果为0,而剩下目标元素与0的异或结果为其本身。这道题目明确要求了时间复杂度为O(N),空间复杂度为O(1),不然借助哈希表很容易能够在O(N)的空间复杂度下解决。特殊的要求只能特殊处理,解这道题只能记住。异或是对二进制数进行位运算,相同为0,相异为1(这种较特殊的运算方式。
2024-08-18 15:38:51
345
原创 70 爬楼梯
但空间复杂度可以进一步优化。观察计算公式,其实并不需要记录每个。看做一个二进制数表示(如1101),每一位都有一个“基数” =的值,后面的数只要不断查表并将其相加就可以了。快速幂可以用在一些齐次线性递推式中,形如。凑出如上形式,但其实不太常用,了解就好了。的数位对应的“基数”相乘,就可以得到。的值就足够了,这样空间复杂度达到了。如果不满足齐次线性递推式,可以构建。我们可以通过列表的方法记录每个。,这样将时间复杂度可以达到。解题思路一:(动态规划)解题思路二:(快速幂),只要将二进制表示中为。
2024-08-18 00:45:38
758
原创 121 买卖股票的最佳时机
由于是从前向后逐个遍历,很容易可以记录之前股票价格的最小值,遍历完成后将最大差值输出即可。,提交后会超时,所以需要在此基础上进行优化,能否通过一次遍历找出最大利润。这个题如果把每一种买卖的可能都算出来的解法时间复杂度在。,卖出股票所能得到的最大利润 = 当前股票价格 -天股票价格的最小值。
2024-08-15 00:03:28
209
原创 543 二叉树的直径
说明:如果有多个转折点,那么路径上会产生分支,该路径不为合法路径;若没有转折点,可将末尾节点的另外一个子节点加入路径,该路径不是最长的;每一条最长路径中一定存在一个转折点 + 若干非转折点(见说明),只需要把每一个点看做转折点,然后开始构建最长路径,从这些路径长度中选取最大值,即为树的直径。那么,如何构建最长的路径呢,很简单,可以通过递归来解决,在递归之中每一步,情况一:该节点为非转折点,最长路径经过其。作为非转折点能构建的最长的路径长度。情况二:该节点为转折点,最长路径经过其。为转折点构建的路径长度。
2024-08-13 22:15:49
445
原创 20 有效的括号
则检查栈顶元素是否与之匹配,匹配则将其出栈,否则返回字符串无效。最后检查栈是否为空,为空时字符串有效。本题最难的点是想到用栈来解决。想到栈以后,事情就变得简单了。将左右括号做一个快速映射,代码看起来更精简些。代码部分可以改进的点,在于可以借助。)将其压入栈中,若为右括号(
2024-08-10 15:48:57
265
原创 35 搜索插入位置
由于本题中,有序数组中无重复元素,且如果没找到此元素时,返回要插入的位置,可以使用模版一来解决。与目标值的比较结果,更新下一次搜索区间(左半边或右半边),直至区间大小为1。二分其实是有模版的,而且有两种:一种是从左向右找到第一个。内,题目存在一中特殊情况,即所有元素小于。初始化为[0, N-1]。的位置,即该位置左边的所有元素均小于。二分基本思路是,通过锚定一个中间值。),另一种是从右向左找到第一个。,可知此题用二分查找解决。,把搜索区间一分为二,根据。有一点需要注意:由于。
2024-08-08 00:44:48
1451
原创 108 将有序数组转换为二叉搜索树
由平衡可知左右子树的节点数量近似相等,相差不应超过一。建树的时候,从数组的最中间选择作为根节点,有序数组的左边组成左子树,数据右边组成右子树,直至完成几个。
2024-08-06 00:20:35
264
原创 101 对称二叉树
迭代可以使用BFS,同时存两个子树的节点,并将其相邻排列,比较队列中相邻两个节点是否值相同。左子树和右子树之间是轴对称的,这两部分可以通过左右翻转相互转化。使用两个指针,同时遍历左右子树,并比较左右节点的值,在寻找下一个节点时,进行翻转即可。解这道题的关键在于,如何理解轴对称的二叉树。
2024-08-03 13:27:33
311
原创 94 二叉树的中序遍历
利用栈,对二叉树进行深度优先搜索,按照“左 — 中 — 右”的方式输出。中序遍历的起始点为该树最左边的非空元素。本题可以使用递归、DFS(迭代)解决。重复的基础操作:输出。左边的所有节点,输出。
2024-08-01 00:09:00
237
原创 226翻转二叉树
树相关的题,大部分都可以通过递归来解决。因为树结构(尤其是二叉树)天然地具有递归发展的性质:对于二叉树的每个树节点,都有一个左节点和一个右节点,且能无限重复延伸。所以对于使用递归方法解题,最重要的是需要确定,对每个节点,不断重复的基础操作是什么。对于本题,翻转二叉树来说,将每个节点的。,可完成翻转,即使子节点为。也没关系,无需特殊处理。
2024-07-31 22:46:31
276
原创 104 二叉树的最大深度
STL时间复杂度总结 https://blog.csdn.net/2302_79440616/article/details/139326935。对于每个节点,将左子树的最大深度与右子树的最大深度比较,选取较大值+1,即为当前节点树的最大深度。空节点的最大深度为0.从根节点开始,每次将同深度的节点加入队列,再遍历队列节点,将其左右子节点加入队列。DFS:一般用 递归 or 迭代+栈。再次回顾C++STL 队列数据结构queue的用法。BFS:一般用 迭代+队列。最大深度可以想到使用。(广度优先)来解决。
2024-07-30 23:52:04
360
原创 141 环形链表
存在环的条件下,如何证明两指针一定会享相遇呢?最容易想到的方法,就是遍历链表同时用哈希表。但能不能更进一步优化空间复杂度到。如果链表不存在环,则。为所有自然数,所以一定能够到达。遇到重复节点则认为存在环,返回。这种方法简单直接,时间复杂度。会在环中绕圈,直到某一时刻与。,则链表中不存在环,返回。- 为链表中环的长度。借用双指针的思路,用。每次前进1步,快指针。
2023-12-12 22:29:24
172
原创 234 回文链表
由于链表的结构特点,访问链表中的元素的时间复杂度为O(n)。相比较而言,使用数组会方便很多,实现O(1)访问。所以这个题,可以先遍历一遍把数值存到数组中,再使用双指针判断是否是回文。
2023-12-05 22:22:57
196
原创 206 反转链表
用于重复将当前节点添加到链表末尾,被函数各层调用使用,一开始的思路是,是用全局变量去存储链表末尾,并在每次操作后不断更新。:通过函数调用其自身,完成目标。另外需要注意的点,由于每次操作是重复的,如果仅仅改变指针的指向会导致反转后的链表未能指向。现在,函数递归到节点2,如何找到翻转链表的末尾?思路大致相同,但是能否优化无需使用全局变量来存储链表末尾?,用于题目输出,只能作为递归函数的返回值传递。,因此在每一步操作中,需额外将反转链表末尾指向。2)目标拆解后,函数每一步需要。,作为翻转后链表的表头。
2023-12-04 21:54:49
186
原创 160 相交链表
相交,则它们之间的区别就仅在于相交节点之前的部分(其实任意两个链表最终都会相交,最坏相交于NULL节点)。这个思路虽然可行,但略显繁琐。对于不同的情况需要分类讨论,因而导致代码写起来非常复杂。如果在相交前,到达了链表末尾,则下一节点将是另一条链表的起始节点。3、较长的链表经过差值处理后,遍历两链表检查是否存在相交点。的距离相等,指针能同时到达。这种交叉遍历的方式,巧妙兼容了。,若两链表不相交,两指针最终一定会同时到达。两个链表,直到它们遇到相交节点(1、找到两个链表较长的那个;,若相交,相交节点到。
2023-11-27 22:01:56
177
原创 283 移动零
这个思路虽然可行,但实现代码仍有些繁琐,需要同时移动两个指针,并且考虑两个指针的范围问题。要创造自己一个假设,并在每一步都要做与假设一致的操作,维持假设成立,最后将假设变成“现实”。:假设以其为分界点,左边均为非零元素,右边均为0元素;:不断向右探索的指针,直至遍历到数组最后一个元素停止。右移1,以保证假设成立。若数组中无0元素,在移动过程中。若任意一个指针到达数组末尾时停止。,找到第一个非零元素时交换二者的值;每次仅移动一次指针(很多算法题的解题思路,都与。右边第一个非零元素坐标。始终指向第一个0元素。
2023-10-15 22:47:08
518
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人