剑指offer:链表中环的入口结点
题意描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解题思路
一、使用集合
使用一个Set/List集合,遍历链表,当出现第一个重复节点时,就是环的节点。
public ListNode EntryNodeOfLoop(ListNode pHead){
if(pHead == null) return null; //链表为空
HashSet<ListNode> set = new HashSet<>();
ListNode node = pHead;
while(node != null){
if(set.contains(node)){ //出现重复节点
return node;
}else{
set.add(node);
node = node.next;
}
}
return null;
}
二、使用快慢指针
使用两个指针,快指针fast,慢指针slow。
让两个指针从头向后移动,fast每次移动两个节点,slow每次移动一个节点,如果链表存在环的话,两个指针一定会相遇。在相遇时,假设slow走了x步,那么fast一定走了2x步。
同时,可以发现fast多走的x步一定是走在环上,也就是说,x是环的长度n的整数倍,即有如下公式: 2x=x+k∗nk=1,2,3,…
也就说,让一个指针指向环上的相遇点,一个指针指向头结点,同时以步长为1往后走,其碰头的那个结点,就是入口结点。
public ListNode EntryNodeOfLoop(ListNode pHead){
if(pHead == null || pHead.next == null) return null;
ListNode fast = pHead.next.next; //快指针
ListNode slow = pHead.next; //慢指针
while(fast != null){
if(fast == slow){ //找到fast 与 slow 的相遇节点
fast = pHead;
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast; //返回两指针再次相遇的节点
}
fast = fast.next.next;
slow = slow.next;
}
return null;
}

浙公网安备 33010602011771号