- 博客(65)
- 收藏
- 关注
原创 python-leetcode 64.在排序数组中查找元素的第一个和最后一个位置
二分查找中,寻找 leftIdx 即为在数组中寻找第一个大于等于 target 的下标,寻找 rightIdx 即为在数组中寻找第一个大于 target 的下标,然后将下标减一。两者的判断条件不同,定义binarySearch(nums, target, lower) 表示在 nums 数组中二分查找 target 的位置,如果 lower 为 true,则查找第一个大于等于 target 的下标,否则查找第一个大于 target 的下标。时间复杂度: O(logn) ,其中 n 为数组的长度。
2025-04-02 22:27:20
232
原创 python-leetcode 63.搜索二维矩阵
由于每行的第一个元素大于前一行的最后一个元素,且每行元素是升序的,所以每行的第一个元素大于前一行的第一个元素,因此矩阵第一列的元素是升序的。对矩阵的第一列元素二分查找,找到最后一个不大于目标值的元素,然后在该元素所在行中二分查找目标是否存在。若将矩阵每一行拼接在上一行的末尾,则会得到一个升序数组,我们可以在该数组上二分找到目标元素。时间复杂度:O(logm+logn)=O(logmn),其中mn分别是矩阵的行数和列数。时间复杂度:O(logm+logn)=O(logmn),其中mn分别是矩阵的行数和列数。
2025-04-02 21:52:19
203
原创 python-leetcode 62.搜索插入位置
问题转化到这个,直接套用二分法即可,即不断用二分法逼近查找第一个大于等于target的下标,ans初始设置为数组长度可以省略边界条件的判断,因为存在一种情况是target大于数组中的所有数,此时需要插入到数组长度的位置。假设题意是在排序数组中寻找是否存在一个目标值,则可以利用二分法在Ologn的时间内找到是否存在目标值,但这题还有个额外条件,即如果不存在数组中的时候需要返回按顺序插入的位置。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。时间复杂度:O(logn)其中n为数组的长度。
2025-04-01 21:05:04
187
原创 python-leetcode 61.N皇后
每次新放置的皇后都不能和已经放置的皇后之间有攻击:即新放置的皇后不能和任何一个已经放置的皇后在同一列以及同一条斜线上,并更新数组中的当前行的皇后列下标。其中,第 4 列为其前两行的第 2 列的皇后往右下移动两步的位置,第 5 列为其前一行的第 4 列的皇后往右下移动一步的位置。其中,第 0 列为其前两行的第 2 列的皇后往左下移动两步的位置,第 3 列为其前一行的第 4 列的皇后往左下移动一步的位置。每次放置皇后时,三个整数的按位或运算的结果即为不能放置皇后的位置,其余位置即为可以放置皇后的位置。
2025-03-31 22:15:04
725
原创 python-leetcode 59.单词搜索
设函数 check(i,j,k) 表示判断以网格的 (i,j) 位置出发,能否搜索到单词 word[k..],其中 word[k..] 表示字符串 word 从第 k 个字符开始的后缀子串。对每一个位置 (i,j) 都调用函数 check(i,j,0) 进行检查:只要有一处返回 true,就说明网格中能够找到相应的单词,否则说明不能找到。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中相邻单元格是那些水平相邻或者垂直相邻的单元格,同一个单元格的字母不允许被重复使用。空间复杂度:O(MN)。
2025-03-31 21:02:43
334
原创 python-leetcode 60.分割回文串
给定一个字符串S,请将S分割成一些子串,使每个子串都是回文串,返回S所有可能的分割方案。时间复杂度:O(n2n),其中 n 为 s 的长度。空间复杂度:O(n)
2025-03-20 21:53:52
305
原创 python-leetcode 58.括号生成
可以只在序列仍然保持有效时才添加 ‘(’ 或 ‘)’,通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,如果左括号数量不大于 n,我们可以放一个左括号。任何一个括号序列都一定是由 ‘(’ 开头,并且第一个 ‘(’ 一定有一个唯一与之对应的 ‘)’,每一个括号序列可以用 (a)b 来表示,其中 a 与 b 分别是一个合法的括号序列(可以为空)。时间复杂度:O(4*n/n**1/2),在回溯过程中,每个答案需要 O(n) 的时间复制到答案数组中。时间复杂度:O(4*n/n**1/2)
2025-03-19 22:04:08
326
原创 python-leetcode 57.组合总和
给一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target所有不同组合,并以列表形式返回,可以按任意顺序返回这些组合。candidates中的同一个数字可以无限制重复被选取,如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为target的不同组合数少于150个。
2025-03-18 22:03:46
169
原创 python-leetcode 56.电话号码的字母组合
首先使用哈希表存储每个数字对应的所有可能的字母,然后进行回溯操作。回溯过程中维护一个字符串,表示已有的字母排列,该字符串初始为空。每次取电话号码的一位数字,从哈希表中获得该数字对应的所有可能的字母,并将其中的一个字母插入到已有的字母排列后面,继续处理电话号码的后一位数字,直到处理完电话号码中的所有数字,即得到一个完整的字母排列。给定一个仅包含数字的2-9的字符串,返回所有它可能表示的字母组合,答案可以按任意顺序返回。给出数字到字母的映射如下(与电话按键相同),注意1不对应任何字母。
2025-03-18 21:15:38
254
原创 python-leetcode 55.子集
我们用 1 表示「在子集中」,0 表示不在子集中,,那么每一个子集可以对应一个长度为 n 的 0/1 序列,第 i 位表示 ai 是否在子集中。│ │ │ └── dfs(3) → 添加 [1, 2, 3]│ │ └── dfs(3) → 添加 [1, 2]│ │ └── dfs(3) → 添加 [1, 3]│ │ └── dfs(3) → 添加 [2, 3]└── dfs(3) → 添加 []
2025-03-17 22:48:30
962
原创 python-leetcode 54.全排列
具体来说,假设已经填到第 first 个位置,那么 nums 数组中 [0,first−1] 是已填过的数的集合,[first,n−1] 是待填的数的集合,尝试用 [first,n−1] 里的数去填第 first 个数,假设待填的数的下标为 i,么填完以后将第 i 个数和第 first 个数交换,即能使得在填第 first+1 个数的时候 nums 数组的 [0,first] 部分为已填过的数,[first+1,n−1] 为待填的数,回溯的时候交换回来即能完成撤销操作。),其中 n 为序列的长度。
2025-03-17 21:28:36
309
原创 python-leetcode 53.实现Trie(前缀树)
推广到 26 种字母,其实就是一棵 26 叉树,对于 26 叉树的每个节点,可以用哈希表,或者长为 26 的数组来存储子节点。search:例如查找字符串 aab,相当于查找二叉树中是否存在一条移动方向为「左-左-右」的路径,且最后一个节点是终止节点。空间复杂度:O(∣T∣⋅Σ),其中 ∣T∣ 为所有插入字符串的长度之和,Σ 为字符集的大小,本题 Σ=26。时间复杂度:初始化为 O(1),其余操作为 O(∣S∣),其中 ∣S∣ 是每次插入或查询的字符串的长度。从字典树的根开始,插入字符串。
2025-03-14 21:53:36
347
原创 python-leetcode 52.课程表
新建一个数组,课程序号作为索引,先修课程的数目入度作为值,入度为0表示先修课程已经完成,或者没有先修课程,现在可以学习这门课程。先学习C1,则以C1为入度的课程值可以减1,C3和C8的入度值减1,此时C8的值为0,将其加入带学习的对列。开始学习C2,C2学习完后,C3,C5减去1,C3,C5的入度为0,加入待学习的对列。如果某一门课程的出度为0表示为相对高阶的课程,出度不为0表示它一定是其他某些课程的先修课程,由浅入深,优先寻找高阶的课程,引入三个状态,依次寻找高阶课程。请判断是否可能完成所有课程的学习?
2025-03-14 20:47:40
461
原创 python-leetcode 51.腐烂的橘子
为了确认是否所有新鲜橘子都被腐烂,可以记录一个变量 cnt 表示当前网格中的新鲜橘子数,广度优先搜索的时候如果有新鲜橘子被腐烂,则 cnt=cnt−1 ,最后搜索结束时如果 cnt 大于 0 ,说明有新鲜橘子没被腐烂,返回 −1 ,否则返回所有新鲜橘子被腐烂的时间的最大值即可,也可以在广度优先搜索的过程中把已腐烂的新鲜橘子的值由 1 改为 2,最后看网格中是否有值为 1 即新鲜的橘子即可。最后的答案就是所有新鲜橘子被腐烂的最短时间的最大值,如果是无限大,说明有新鲜橘子没有被腐烂,输出 −1 即可。
2025-03-14 10:22:03
507
原创 python-leetcode 50.岛屿数量
为了求出岛屿的数量,可以扫描整个二维网格。在深度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。为了求出岛屿的数量,我们可以扫描整个二维网格,如果一个位置为 1,则将其加入队列,开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0。空间复杂度:O(min(M,N)),在最坏情况下,整个网格均为陆地,队列的大小可以达到 min(M,N)给定一个由“1”陆地和“0”水组成的网格,请计算网格中岛屿的数量。最终岛屿的数量就是我们进行广度优先搜索的次数。
2025-03-12 22:16:09
334
原创 python-leetcode 49.二叉树中的最大路径和
对于二叉树中的一个节点,该节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值,如果子节点的最大贡献值为正,则计入该节点的最大路径和,否则不计入该节点的最大路径和。首先,考虑实现一个简化的函数 maxGain(node),该函数计算二叉树中的一个节点的最大贡献值,具体而言,就是在以该节点为根节点的子树中寻找以该节点为起点的一条路径,使得该路径上的节点值之和最大。非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和(对于叶节点而言,最大贡献值等于节点值),即可得到每个节点的最大贡献值。
2025-03-12 20:58:17
237
原创 python-leetcode 48.二叉树的最近公共祖先
其中 lson 和 rson 分别代表 x 节点的左孩子和右孩子,flson && frson 说明左子树和右子树均包含 p 节点或 q 节点,如果左子树包含的是 p 节点,那么右子树只能包含 q 节点,反之亦然,因为 p 节点和 q 节点都是不同且唯一的节点,因此如果满足这个判断条件即可说明 x 就是我们要找的最近公共祖先。递归调用的栈深度取决于二叉树的高度,二叉树最坏情况下为一条链,此时高度为 N,因此空间复杂度为 O(N),哈希表存储每个节点的父节点也需要 O(N) 的空间复杂度。
2025-03-04 22:14:27
418
原创 python-leetcode 47.路径总和III
假设当前的节点 p 的值为 val,对左子树和右子树进行递归搜索,对节点 p 的左孩子节点 pi求出rootSum(pl,targetSum-val).以l及对右孩子节点P求出rootSum(pr,targetSum-val),节点 p 的root(p.targetSum)即等于rootSum(pl,targetSum-val)与rootSum(pr,targetSum-val)之和同时我们还需要判断一下当前节点 p 的值是否刚好等于 targetSum。时间复杂度:O(N2)N 为该二叉树节点的个数。
2025-03-04 20:05:43
802
原创 python-leetcode 46.从前序与中序遍历序列构造二叉树
在中序遍历中对根节点进行定位时,一种简单的方法是直接扫描整个中序遍历的结果并找出根节点,但这样做的时间复杂度较高。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有。这样以来,就知道了左子树的前序遍历和中序遍历结果,以及右子树的前序遍历和中序遍历结果,我们就可以递归地对构造出左子树和右子树,再将这两颗子树接到根节点的左右位置。[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]前序遍历:0[root[左子树][右子树]]n-1。
2025-02-27 22:44:25
307
原创 python-leetcode 45.二叉树转换为链表
如果一个节点的左子节点不为空,则该节点的左子树中的最后一个节点被访问之后,该节点的右子节点被访问。该节点的左子树中最后一个被访问的节点是左子树中的最右边的节点,也是该节点的前驱节点。对于当前节点,如果其左子节点不为空,则在其左子树中找到最右边的节点,作为前驱节点,,将当前节点的右子节点赋给前驱节点的右子节点,然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。前序遍历的时间复杂度是 O(n),前序遍历之后,需要对每个节点更新左右子节点的信息,时间复杂度也是 O(n)。
2025-02-27 20:20:50
418
原创 python-leetcode 44.二叉树的右视图
执行广度优先搜索,左结点排在右结点之前,这样,我们对每一层都从左到右访问。因此,只保留每个深度最后访问的结点,我们就可以在遍历完整棵树后得到每个深度最右的结点。以对二叉树进行层次遍历,那么对于每层来说,最右边的结点一定是最后被遍历到的。每个节点最多进队列一次,所以队列长度最大不不超过 n,所以这里的空间代价为 O(n)。空间复杂度:O(n)最坏情况下,栈内会包含接近树高度的结点数量,占用 O(n) 的空间。可以存储在每个深度访问的第一个结点,一旦知道了树的层数,就可以得到最终的结果数组。
2025-02-26 21:27:47
329
原创 python-leetcode 43.二叉搜索树中第K小的元素
如果 node 的左子树的结点数 left 小于 k−1,则第 k 小的元素一定在 node 的右子树中,令 node 等于其的右子结点,k 等于 k−left−1,并继续搜索;搜索的时间复杂度为 O(H),其中 H 是树的高度;如果 node 的左子树的结点数 left 大于 k−1,则第 k 小的元素一定在 node 的左子树中,令 node 等于其左子结点,并继续搜索。如果 node 的左子树的结点数 left 等于 k−1,则第 k 小的元素即为 node ,结束搜索并返回 node 即可。
2025-02-25 21:25:55
375
原创 python-leetcode 42.验证二叉搜索树
根据二叉搜索树的性质,在递归调用左子树时,我们需要把上界 upper 改为 root.val,即调用 helper(root.left, lower, root.val),因为左子树里所有节点的值均小于它的根节点的值。而我们二叉搜索树保证了左子树的节点的值均小于根节点的值,根节点的值均小于右子树的值,因此中序遍历以后得到的序列一定是升序序列。二叉搜索树「中序遍历」得到的值构成的序列一定是升序的,这启示我们在中序遍历的时候实时检查当前节点的值是否大于前一个中序遍历到的节点的值即可。空间复杂度:O(n)
2025-02-24 21:55:54
477
原创 python-leetcode 41.将有序数组转换为二叉搜索树
如果数组长度是奇数,则根节点的选择是唯一的,如果数组长度是偶数,则可以选择中间位置左边的数字作为根节点或者选择中间位置右边的数字作为根节点,选择不同的数字作为根节点则创建的平衡二叉搜索树也是不同的。确定平衡二叉搜索树的根节点之后,其余的数字分别位于平衡二叉搜索树的左子树和右子树中,左子树和右子树分别也是平衡二叉搜索树,因此可以通过递归的方式创建平衡二叉搜索树。二叉搜索树的中序遍历是升序序列,题目给定的数组是按照升序排序的有序数组,因此可以确保数组是二叉搜索树的中序遍历序列。
2025-02-24 20:21:49
330
原创 python-leetcode 40.二叉树的层序遍历
给定二叉树的根节点root,返回其节点值得层序遍历(即逐层从左到右访问所有节点)时间复杂度:O(n)空间复杂度:O(n)时间复杂度:O(n)空间复杂度:O(n)
2025-02-20 22:04:09
226
原创 python-leetcode 39.二叉树的直径
先递归调用左儿子和右儿子求得它们为根的子树的深度L和R,则该节点为根的子树的深度即为max(L,R)+1该节点的d node值为L+R+1递归搜索每个节点并设一个全局变量ans记录dnode的最大值,最后返回ans-1即为树的直径。假设知道对于该节点的左儿子向下遍历经过最多的节点数L(即以左儿子为根的子树的深度) 和其右儿子向下遍历经过最多的节点数R(即以右儿子为根的子树的深度),那么以该节点为起点的路径经过节点数的最大值即为L+R+1。二叉树的直径是指中间任意两个节点之间最长路径的长度。
2025-02-20 21:26:05
357
原创 python-leetcode 38.翻转二叉树
每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。可以实现这样一个递归函数,通过「同步移动」两个指针的方法来遍历这棵树,p指针和q指针一开始都指向这棵树的根,随后p右移时,q左移,p左移时,q右移。互为镜像的条件:他们的两个根结点具有相同的值,每棵树的右子树都与另一个树的左子树镜像对称。如果一个树的左子树与右子树镜像对称,那么这个树是对称的。时间复杂度:O(n)空间复杂度:O(n)空间复杂度:O(n)
2025-02-20 21:04:40
325
原创 python-leetcode 37.翻转二叉树
从根节点开始,递归地对树进行遍历,并从叶子节点先开始翻转。如果当前遍历到的节点root的左右两棵子树都已经翻转,那么我们只需要交换两棵子树的位置,即可完成以root为根节点的整棵子树的翻转。给定一颗二叉树的根节点root,翻转这棵二叉树,并返回根节点。时间复杂度:O(n)遍历二叉树中的每一个节点。空间复杂度:O(n)
2025-02-19 21:34:54
307
原创 python-leetcode 36.二叉树的最大深度
因此可以用「深度优先搜索」的方法来计算二叉树的最大深度。具体而言,在计算当前二叉树的最大深度时,可以先递归计算出其左子树和右子树的最大深度,然后在O(1)时间内计算出当前二叉树的最大深度。广度优先搜索的队列里存放的是「当前层的所有节点」。每次拓展下一层的时候,用一个变量ans来维护拓展的次数,该二叉树的最大深度即为ans。知道了左子树和右子树的最大深度l和r,那么该二叉树的最大深度即为:max(l,r)+1。每个节点在递归中只被遍历一次。二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。
2025-02-19 21:19:49
257
原创 python-leetcode 35.二叉树的中序遍历
给定一个二叉树的根节点root,返回它的中序遍历。二叉树的中序遍历:按照访问左子树——根节点——右子树的方式遍历这棵树,而在访问左子树或者右子树的时候我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质。
2025-02-19 20:39:55
490
原创 python-leetcode 34.合并K个升序链表
一个巧妙的思路是,把lists一分为二(尽量均分),先合并前一半的链表,再合并后一半的链表,然后把这两个链表合并成最终的链表。如此分下去直到只有一个链表,此时无需合并。维护当前每个链表没有被合并的元素的最前面一个,k个链表就最多有k个满足这样条件的元素,每次在这些元素里面选取val属性最小的元素合并到答案中。给定一个链表数组,每个链表都已经按升序排序,请将所有链表合并到一个升序链表中,返回合并后的链表。按照方法一先合并前两个链表,再把得到的新链表和第三个链表合并,再和第四个链表合并,依此类推。
2025-02-18 20:04:54
406
原创 python-leetcode 33.排序链表
每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength)按照每两个子链表一组进行合并,合并后即可得到若干个长度为subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。合并两个子链表仍然使用[合并两个有序链表]的做法。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。3.将两个排序后的子链表合并,得到完整的排序后的链表。
2025-02-18 11:26:23
335
原创 python-leetcode 32.随机链表的复制
例如链表 1→2→3,依次复制每个节点(创建新节点并复制 val 和 next),把新节点直接插到原节点的后面,形成一个交错链表:1→1 ′→2→2 ′ →3→3 ′ 如此一来,原链表节点的下一个节点,就是其对应的新链表节点了!复制链表中的指针都不应指向原链表中的节点。一个可行方案是,利用回溯的方式,让每个节点的拷贝操作相互独立,对于当前节点,首先要进行拷贝,然后我们「当前节点的后继节点」和「当前节点的随机指针指向的节点」拷贝,拷贝完成后将创建的新节点的指针返回,即可完成当前节点的两指针的赋值。
2025-02-17 17:18:34
710
原创 python-leetcode 31.K个一组翻转链表
但是对于一个子链表,除了翻转其本身之外,还需要将子链表的头部与上一个子链表连接,以及子链表的尾部与下一个子链表连接。K是正整数,它的值小于等于链表的长度,如果节点总数不是K的整数组,那么将最后剩余的节点保持原有顺序。不能只改变节点内容的值,需要进行实际的节点交换。给定链表的头节点head,每K个节点一组进行翻转,返回修改后的链表。步,直至链表结尾,对于每个分组,我们先判断它的长度是否大于等于。的,们新建一个节点,把它接到链表的头部,让它作为。在翻转子链表的时候,我们不仅需要子链表头节点。
2025-02-13 22:02:44
459
原创 python-leetcode 30.两两交换链表中的节点
如果链表中至少有两个节点,则在两两交换链表中的节点之后,原始链表的头节点变成新的链表的第二个节点,原始链表的第二个节点变成新的链表的头节点。用 head 表示原始链表的头节点,新的链表的第二个节点,用 newHead 表示新的链表的头节点,原始链表的第二个节点,则原始链表中的其余节点的头节点是 newHead.next。两两交换链表中的节点之后,新的链表的头节点是 dummyHead.next,返回新的链表的头节点即可。递归的终止条件是链表中没有节点,或者链表中只有一个节点,此时无法进行交换。
2025-02-13 21:02:26
270
原创 python-leetcode 29.删除链表的倒数第N个结点
根据栈「先进后出」的原则,我们弹出栈的第 n 个节点就是需要删除的节点,并且目前栈顶的节点就是待删除节点的前驱节点。首先从头节点开始对链表进行一次遍历,得到链表的长度 L,随后再从头节点开始对链表进行一次遍历,当遍历到第 L−n+1 个节点时,它就是我们需要删除的节点。在对链表进行操作时,常用的技巧是添加一个哑节点(dummy node),它的 next 指针指向链表的头节点,就不需要对头节点进行特殊的判断。与题目中的 n 保持一致,节点的编号从 1 开始,头节点为编号 1 的节点。时间复杂度:O(N)
2025-02-13 20:09:41
849
原创 python-leetcode 28.两数相加
如果当前两个链表处相应位置的数字为n1,n2,进位为carry,则它们的和为n1+n2+carry。答案链表处相应位置的数字为 (n1+n2+carry)mod10,而新的进位值为(n1+n2+carry)//10。这里的技巧是,创建一个哨兵节点(dummy node),当成初始的「空链表」。由于输入的两个链表都是逆序(链表顺序反向)存储数字的位数的,因此两个链表中同一位置的数字是可以直接相加。此外,如果链表遍历结束后,有carry>0,还需要在答案后面附加一个节点,节点值为carry。
2025-02-12 22:08:18
412
原创 python-leetcode 27.合并两个有序链表
由于输入的两个链表都是有序的,所有不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大,所以,只需要简单地将非空链表接在合并链表地后面,并返回合并链表即可。否则要判断L1和l2哪一个链表的头节点的值更小,然后递归的决定下一个添加结果里的节点,如果两个链表有一个为空,递归结束。当l1和l2都不是空链表时,判l1和l2哪一个链表的头节点的值更小,将较小值得节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中得节点向后移动一位。新链表是通过拼接给定的两个链表的所有节点组成的。
2025-02-12 21:14:56
382
原创 python-leetcode 26.环形链表II
此时,fast 指针已经走完了环的 n 圈,因此它走过的总距离为 a+n(b+c)+b=a+(n+1)b+nc。时间复杂度:O(N)在最初判断快慢指针是否相遇时,slow 指针走过的距离不会超过链表的总长度;因此,总的执行时间为 O(N)+O(N)=O(N)。有了 a=c+(n−1)(b+c) 的等量关系,发现:从相遇点到入环点的距离加上 n−1 圈的环长,恰好等于从链表头部到入环点的距离。因此,有a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c)指针再次到达,则链表中存在环。
2025-02-11 21:36:22
428
原创 python-leetcode 25.环形链表
因此,可以假想一个head之前的虚拟节点,慢指针从虚拟节点移动一步到达head,快指针从虚拟节点移动两步到达head.next,这样可以使用while循环。如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。具体使用哈希表来存储访问过的节点,每次到达一个节点,如果该节点已经存在于哈希表中,则说明该链表是环形链表,否则就将该节点加入哈希表。空间复杂度:O(1)
2025-02-11 20:57:31
381
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人