本文主要记录了博主的 Leetcode 算法刷题记录,方便以后查询复习。
链表
相交链表
哈希表存储遍历的节点,然后进行操作。第二种方法技巧性比较强,利用路径长度相同会回到相交的点的做法来求解。
反转链表
循环和递归,递归比较难以理解,参考意义不是很大。
回文链表
将值放在数组中然后进行判断
环形链表
哈希表与快慢指针,无需多言。🥰
环形链表 Ⅱ
哈希表与快慢指针求解,第二种方法技巧性比较强,参考性不是很高。
合并两个有序链表
有递归和循环两种写法。
两数相加
注意进位的处理与归零,其他的都比较简单,思路正确照着写就行。
删除链表的倒数第 N 个节点
采用计算链表长度或者双指针进行求解
两两交换链表中的节点
注意指针需要用temp.next.next
,便于直接删除。
k 个一组翻转链表
该题思路比较简单,但处理情况比较繁琐,十分考量面试者的代码设计能力,推荐将可以翻转的判断与翻转函数书写,同时需要注意翻转后的链表需要连接回原来的链表,所以需要保留上一链表的节点,所以翻转的时候推荐使用temp.next
进行翻转。
随机链表的复制
采取哈希表存储原链表与复制之后链表之间节点的对应关系,从而实现复制功能,还可以通过递归实现,但基本思路大致相同
排序链表
使用归并排序的思路,求解,左闭右开,同时注意fast
指针需要严格遵守fast !== tail
的规则来使用。
合并 k 个升序链表
分治与归并排序,掌握思路就比较简单。
LRU 算法
双向链表加上哈希表解决,算法不难,重点是了解其基本思想,注意过量操作需要删除节点。
二叉树
二叉树的前序遍历
可采用递归和迭代的两种方式,详细理解一下前序遍历迭代的套路。
- 维护一个结果
res
与栈stack
。
- 采用
while
循环循环压入栈,判断条件为root || stack.length
。
- 与中序遍历的区别在于在内部
while
循环中需要推入res
数组,而不是在外部推入。
- 注意在循环向左压入数字,栈需要更新
root
,而不是新建一个变量。
二叉树的中序遍历
可采用递归和迭代的两种方式,详细理解一下中序遍历迭代的套路。
- 维护一个结果
res
与栈stack
。
- 采用
while
循环循环压入栈,判断条件为root || stack.length
。
- 注意在循环向左压入数字,栈需要更新
root
,而不是新建一个变量。
二叉树的后序遍历
可采用递归和迭代的两种方式,详细理解一下后序遍历迭代的套路。
- 维护一个结果
res
与栈stack
。
- 采用
while
循环循环压入栈,判断条件为root || stack.length
。
- 注意在循环向左压入数字,栈需要更新
root
,而不是新建一个变量。
- 注意与中序遍历不同的是需要将父节点推入
stack
同时在“触底”的时候记录right
变量,防止再一次回溯。
二叉树的最大深度
采取递归的思路求解,推荐使用回溯算法,即每个节点从叶子节点开始回溯,每次都返回当前节点左右子节点的最大深度加一,最后返回根节点的最大深度。
翻转二叉树
也是同样的回溯思想,叶子节点开始反转,一直反转到根节点,核心思路为先递归到叶子节点然后一步步返回。
对称二叉树
初看这个题目或许比较复杂,但简而言之还是按照深度一层层比较,掌握技巧后就比较简单,注意的是判断条件和递归和迭代的实现思路的细微区别。
二叉树的直径
由二叉树的最大深度稍加改进而来,还是一样,先递归到子节点,然后回溯返回。
二叉树的层序遍历
层序遍历属于广度优先遍历,与深度优先遍历不同,广度优先遍历一般使用队列与循环完成。不需要二维数组,每次遍历都清空queue
。
这个算法有两个需要注意的点
- 只有值不为空的节点才能推入下一次需要遍历的队列。
- 注意当下一次需要遍历的队列为空的时候,不能推入,防止死循环。
将有序数组转化为二叉搜索树
查看二叉搜索树的详细解释
当然可以。二叉搜索树(Binary Search Tree,简称 BST),也称为二叉查找树或二叉排序树,是一种特殊的二叉树。它具有以下性质:
有序性:对于树中的任意一个节点,其左子树中的所有节点的值都小于该节点的值,而右子树中的所有节点的值都大于该节点的值。这意味着所有的元素能够通过比较操作被明确地排序。
递归性质:BST 的左子树和右子树也都是二叉搜索树。这意味着 BST 的定义是递归的,我们可以递归地在子树中进行查找和其他操作。
无重复值:在 BST 中,每个元素必须是唯一的,因为树的定义不允许含有相同值的节点。
二叉搜索树的主要优势在于,它结合了链表和数组的优点:链表的快速插入和删除操作,以及数组的快速查找性能。在平均情况下,查找、插入和删除操作的时间复杂度都是 $O(log n)$ ,其中 $n$ 是树中节点的数量。然而,在最坏的情况下,如果树变得不平衡,这些操作的时间复杂度可能会退化到 $O(n)$ 。
二叉搜索树在计算机科学中应用广泛,特别是在那些需要频繁查找、插入和删除数据的场景中,如数据库和文件系统。
采用二分法将有序数组转化为二叉搜索树,判断条件与二分法基本相同,有着相同的边界处理情况。
left = 0, right = nums.length - 1
对应low = 0, high = nums.length - 1
left > right
对应low <= high
验证二叉搜索树
一种方式是采用上下界递归求解,注意左右节点上下界的选取,以及在JS
中正负Infinity
的使用。另一种方法则是利用二叉搜索树的中序遍历是升序序列来进行判断,可采用递归和循环两种方式,循环方式代码更加优雅一些。
二叉搜索树中第 k 小的元素
记住中序遍历的套路直接秒。😍
二叉树的右视图
和层序遍历大致相同,注意基本思路即可。
二叉树展开为链表
采用前序遍历的操作来解决,其实相当于中序遍历迭代写法的变式。因为在内层while
循环中已经开始遍历,所以没有弹出栈后往右遍历的步骤。
从前序与中序遍历序列构造二叉树
这道题技巧性比较强,主要利用了前序数组与中序数组的相关的性质进行求解。进行根元素和左右元素进行分割。其实本质上也是二分,和将有序数组转化为二叉搜索树相同。
路径总和 III
不考虑时间复杂度直接深度遍历暴力求解,考虑时间复杂度可以使用前缀和的方式进行求解。和和为-k-的子数组思路大致相同。
二叉树的最近公共祖先
采用递归的方式求解,注意条件之类的判断,当最深的祖先节点被找到之后,之后的节点不会再满足要求。
主要的判断条件(leftSon && rightSon) || ((p.val === root.val || q.val === root.val) && (leftSon || rightSon))
,返回leftSon || rightSon || root.val === p.val || root.val === q.val
124. 二叉树的最大路径和
在二叉树的直径与最大深度的代码上改良。
二叉树中和为目标值的路径
节省数组空间可采用堆栈弹入或者弹出。