一、题目描述
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例1:
输入: head = [3,2,0,-4], pos = 1 输出: true 解释: 链表中有一个环,其尾部连接到第二个节点。 复制代码
示例2:
输入: head = [1,2], pos = 0 输出: true 解释: 链表中有一个环,其尾部连接到第一个节点。 复制代码
提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为-1
或者链表中的一个 有效索引 。
二、思路分析
这一道题目还是比较考验你的思维能力的,有三种做法
- 第一种做法就是暴力解法,一直循环next,看是否能结束循环,当然这种解法性能一定很差,我们肯定是不推荐的。
- 第二种做法就是使用Set数据结构,遍历到的每个节点将他存起来,Set数据结构的特性就是一组唯一值的集合,关于它的更多的信息可以查看MDN-JavaScript标准内置对象-Set,wow,MDN居然有了新的文档!!!。该做法的时间复杂度是O(n * 1) = O(n)
- 第三种做法就是龟兔赛跑的解法,也就是使用快慢指针,快指针走2步,慢指针走一步,如果链表没有环,那么它们一定不会走到同一节点,如果链表有环,那么它们将会一定相遇,当然这种解法可能比较
反人类
,比较难想到。该做法的时间复杂度也是O(n)
三、AC代码
- Set数据结构解法
const hasCycle = function(head) { const visited = new Set() while(head) { if(visited.has(head)) { return true } visited.add(head) head = head.next } return false }; 复制代码
- 龟兔赛跑解法
var hasCycle = function(head) { let p1 = head, p2 = head while (p1 && p2.next && p2.next.next) { p1 = p1.next p2 = p2.next.next if (p1 === p2) { return true } } return false }; 复制代码
四、总结
这题在思维上还是有一点的,我们推荐使用后面两种解法,Set解法是比较中规中举的解法,龟兔赛跑解法比较反人类,可能你很难想到,它相比于Set解法更加节省内存,因为你不用将每个节点存起来,如果你能在面试的时候能想到这三种解法,那你一定会在面试官面前眼前一亮。