环形链表
今天为大家带来,链表检测成环 的经典题目。如果你觉得你会了,请你不妨耐心些认真看下去,我相信会有一些不一样的收获!还是先从一道题目开始哟,准备好了吗? Let’ s go !
01、题目分析
第141题:环形链表
给定一个链表,判断链表中是否有环。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。
示例 1:
1. 输入:head = [3,2,0,-4], pos = 12. 输出:true3. 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
1. 输入:head = [1,2], pos = 02. 输出:true3. 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
1. 输入:head = [1], pos = -12. 输出:false3. 解释:链表中没有环。

题目可能你会觉得过于简单!但是不妨耐心看完! 则一定会有收获!
02、题目分析
题解一:哈希表判定
思路:通过hash表来检测节点之前是否被访问过 ,来判断链表是否成环。这是最容易想到的一种题解了。过于简单,直接上代码:
1. func hasCycle(head *ListNode) bool {2. m := make(map[*ListNode]int)3. for head != nil {4. if _,exist := m[head];exist {5. return true6. }7. m[head]= 1 98. head = head.Next9. }10. return false1211. }
题解二:JS特殊解法
相信对于 JS 中的 JSON.stringify() 方法大家都用过,主要用于将 JS 对象 转换为 JSON 字符串 。基本使用如下:
1. var car = {2. name: '小喵',3. age: 20,4. }5. var str = JSON.stringify(car);6. console.log(str)7. //=> {"name":"小喵","age":20}
大家想一下,如果是自己实现这样的一个函数,我们需要处理什么样的特殊情况?对,就是循环引用 。因为对于循环引用,我们很难通过 JSON 的结构将其进行展示!比如下面:
1. var a = {}2. var b = {3. a: a4. }5. a.b = b6. console.log(JSON.stringify(a))7. //=> TypeError: Converting circular structure to JSON
那我们思考,对于环形链表,是不是就是一个循环结构呢?当然是!因为只要是环形链表,它一定存在类似以下代码:
a.Next = b b.Next = a 所以我们可以通过 JSON.stringify() 的特性进行求解:
1. var hasCycle = function(head) {2. try{3. JSON.stringify(head)4. }catch(e){5. return true6. }7. return false8. };
当然,这种解法并不是建议的标准题解!在此列出是为了拓宽思维!(大家如有兴趣,可以自己去看下JSON.stringify 内部的实现,是如何检测循环引用的。)
题解三:双指针解法
本题标准解法!常识内容,必须掌握 !
思路来源:先想象一下,两名运动员以不同速度在跑道上进行跑步 会怎么样?相遇 !好了,这道题你会了。
解题方法:通过使用具有 不同速度 的快、慢两个指针遍历链表 ,空间复杂度可以被降低至 O(1)。慢指针每次移动一步,而快指针每次移动两步 。
假设链表为
, 其步骤如下:
分析完毕,直接上代码:
1. func hasCycle(head *ListNode) bool {2. if head == nil {3. return false4. }5. fast := head.Next // 快指针,每次走两步6. for fast != nil && head != nil && fast.Next != nil {7. if fast == head { // 快慢指针相遇,表示有环8. return true9. }10. fast = fast.Next.Next11. head = head.Next // 慢指针,每次走一步12. }13. return false14. }
这里我们要特别说明一下,为什么慢指针的步长设置为 1 ,而快指针步长设置为 2 。
首先,慢指针步长为 1,很容易理解,因为我们需要让慢指针步行至每一个元素 。而快指针步长为 2 ,通俗点可以理解为他们的相对速度只差 1 ,快的只能一个一个格子的去追慢的,必然在一个格子相遇。
如果没看懂,我们来分析:在快的快追上慢的时,他们之间一定是只差 1 个或者 2 个格子。如果落后 1 个,那么下一次就追上了。如果落后 2 个,那么下一次就落后 1 个,再下一次就能追上!如下图:
所以我们的快指针的步长可以设置为 2 。
03、特别说明
我们常会遇到一些所谓的“简单题目“,然后用着前人留下来的那些”经典题解“迅速作答。在解题的过程中,追求公式化、模板化。当然,这个过程是好的,因为社会、工作、学业要求我们如此!但是,我希望我们也可以留下一些自己的思考,纵然不是最优解,但是是我们自己想到的、创造的!真正在算法题中去收获快乐~
整理人:豆包AI助手
