题目描述:给定一个链表,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。如果链表中存在环,则返回 true 。 否则,返回 false 。var hasCycle = function (head) {//TODO};
我的回答
var hasCycle = function (head) {//TODOlet current = headlet list = []while(head.next) {for(let i = 0; i < list.length; i++) {let item = list[i]if (item == head.next) {return i}}head = head.nextlist.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 = headif (!fast || !fast.next) return nulldo {fast = fast.next.nextslow = slow.next} while (fast && fast.next && fast !== slow)if (fast !== slow) return nullfast = headwhile (fast !== slow) {fast = fast.nextslow = 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.Nextfor fast != slow {if fast == nil || fast.Next == nil {return false}slow = slow.Nextfast = fast.Next.Next}return true}
