赞
踩
环形链表II:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
思路:
我们可以使用一个set集合来存储元素,当如果set中有重复值出现是代表有环且为环的入口
算法:
首先,我们分配一个 Set 去保存所有的列表节点。我们逐一遍历列表,检查当前节点是否出现过,如果节点已经出现过,那么一定形成了环且它是环的入口。否则如果有其他点是环的入口,我们应该先访问到其他节点而不是这个节点。其他情况,没有成环则直接返回 null 。
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while(head != null){
if(set.contains(head)){
return head;
}else{
set.add(head);
head=head.next;
}
}
return null;
}
}
思路:
当然一个跑得快的人和一个跑得慢的人在一个圆形的赛道上赛跑,会发生什么?在某一个时刻,跑得快的人一定会从后面赶上跑得慢的人。
算法
Floyd 的算法被划分成两个不同的阶段 。(1)找出列表中是否有环,如果没有环,可以直接返回 null 并退出。(2)用相遇节点来找到环的入口。
阶段1:
这里我们初始化两个指针 - 快指针和慢指针。我们每次移动慢指针一步、快指针两步,直到快指针无法继续往前移动。如果在某次移动后,快慢指针指向了同一个节点,我们就返回它。否则,我们继续,直到 while 循环终止且没有返回任何节点,这种情况说明没有成环,我们返回 null 。
阶段2
给定阶段 1 找到的相遇点,阶段 2 将找到环的入口。首先我们初始化额外的两个指针: ptr1 ,指向链表的头, ptr2 指向相遇点。然后,我们每次将它们往前移动一步,直到它们相遇,它们相遇的点就是环的入口,返回这个节点。
public class Solution { private ListNode getIntersect(ListNode head) { ListNode tortoise = head; ListNode hare = head; // A fast pointer will either loop around a cycle and meet the slow // pointer or reach the `null` at the end of a non-cyclic list. while (hare != null && hare.next != null) { tortoise = tortoise.next; hare = hare.next.next; if (tortoise == hare) { return tortoise; } } return null; } public ListNode detectCycle(ListNode head) { if (head == null) { return null; } // If there is a cycle, the fast/slow pointers will intersect at some // node. Otherwise, there is no cycle, so we cannot find an e***ance to // a cycle. ListNode intersect = getIntersect(head); if (intersect == null) { return null; } // To find the e***ance to the cycle, we have two pointers traverse at // the same speed -- one from the front of the list, and the other from // the point of intersection. ListNode ptr1 = head; ListNode ptr2 = intersect; while (ptr1 != ptr2) { ptr1 = ptr1.next; ptr2 = ptr2.next; } return ptr1; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。