方法一:使用set,遍历链表,如果存在一个已经存在的node,那就说明有环了,此时,返回该节点;否则,当跳出while循环时,说明没有环,则返回None。
# -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def EntryNodeOfLoop(self, pHead): # write code here if pHead.next == None: return None nodes = set() while pHead.next is not None: if pHead not in nodes: nodes.add(pHead) pHead = pHead.next else: return pHead return None方法二:快慢指针,其实这个题目我最早想到的是使用快慢指针。无奈理解不够透彻,写的快慢指针有问题,所以无奈有了上述方法一(使用老流氓set)
思路:定义两个指针slow和fast,不断移动这两个指针,slow指针移动的步长是1,而fast指针移动的步长是2. 如果存在环,则slow指针和fast指针一定会相遇,此时输出该节点。 否则判断fast指针的next是否为空,如果为空的话,说明快指针已经到了链表的尾部,该链表无环。那判断有环之后怎么确定环的入口节点呢?
借鉴官方题解的快慢指针做法。地址:https://blog.nowcoder.net/n/9d3ffa4b004e43d1aff512141d0d7dac
重点理解为什么在第一次相遇之后要将fast指针移动到开头!官方题解中公式推导。
/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } } */ public class Solution { public ListNode EntryNodeOfLoop(ListNode pHead) { ListNode slow = pHead; ListNode fast = pHead; while(fast !=null && fast.next != null){ slow = slow.next; fast = fast.next.next; if (slow == fast) break; } // 判断跳出循环的原因:如果是break的话就是有环,如果是因为不满足while判别条件那就是没有环 if (fast ==null || fast.next == null) return null; // 因为不满足while条件而跳出的 // 得到环的入口节点 fast = pHead; while(slow != fast){ fast = fast.next; slow = slow.next; } return fast; } }快慢指针应用场景:判断是否有环,环的入口,删除倒数第k个元素,找到中间值;