题目描述:
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
var hasCycle = function (head) {
//TODO
};
我的回答
var hasCycle = function (head) {
//TODO
let current = head
let list = []
while(head.next) {
for(let i = 0; i < list.length; i++) {
let item = list[i]
if (item == head.next) {
return i
}
}
head = head.next
list.push(head)
}
return -1
};
参考回答
https://leetcode-cn.com/problems/linked-list-cycle/solution/
// 思路:快慢指针,快的速度是慢的两倍。
// 第一次相遇则是有环,且相遇点距环入口距离加上入环前长度会是环的整数倍。
// 然后从相遇点以及头部同时进行两个指针,相遇时就是环入口
// 关键点:注意边界条件,比如第一次确定有环的遍历时要注意开始条件是fast===slow,不能直接while(fast!==slow)这样;
// 一次移动两次的指针,fast=fast.next.next,条件里应当是fast.next非空进行(非空的fast.next有next),同时也要加上fast非空的条件,避免出现报错(fast为空的时候)
var detectCycle = function (head) {
let fast = head, slow = head
if (!fast || !fast.next) return null
do {
fast = fast.next.next
slow = slow.next
} while (fast && fast.next && fast !== slow)
if (fast !== slow) return null
fast = head
while (fast !== slow) {
fast = fast.next
slow = slow.next
}
return slow
};
LeetCode题解
假想「乌龟」和「兔子」在链表上移动,「兔子」跑得快,「乌龟」跑得慢。当「乌龟」和「兔子」从链表上的同一个节点开始移动时,如果该链表中没有环,那么「兔子」将一直处于「乌龟」的前方;如果该链表中有环,那么「兔子」会先于「乌龟」进入环,并且一直在环内移动。等到「乌龟」进入环时,由于「兔子」的速度快,它一定会在某个时刻与乌龟相遇,即套了「乌龟」若干圈。
我们可以根据上述思路来解决本题。具体地,我们定义两个指针,一快一满。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。
为什么我们要规定初始时慢指针在位置 head,快指针在位置 head.next,而不是两个指针都在位置 head(即与「乌龟」和「兔子」中的叙述相同)?
观察下面的代码,我们使用的是 while 循环,循环条件先于循环体。由于循环条件一定是判断快慢指针是否重合,如果我们将两个指针初始都置于 head,那么 while 循环就不会执行。因此,我们可以假想一个在 head 之前的虚拟节点,慢指针从虚拟节点移动一步到达 head,快指针从虚拟节点移动两步到达 head.next,这样我们就可以使用 while 循环了。
当然,我们也可以使用 do-while 循环。此时,我们就可以把快慢指针的初始值都置为 head。
func hasCycle(head *ListNode) bool {
if head == nil || head.Next == nil {
return false
}
slow, fast := head, head.Next
for fast != slow {
if fast == nil || fast.Next == nil {
return false
}
slow = slow.Next
fast = fast.Next.Next
}
return true
}