这是我参与更文挑战的第7天,活动详情查看: 更文挑战
这题与环形链表这题很类似,这题要求当链表有环时,找到入环地点。
方法一:Set集合
public ListNode detectCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<>();
while (head != null) {
if (!set.add(head)) {
return head;
}
head = head.next;
}
return null;
}
通过遍历链表,用HashSet存储每个遍历的元素,当添加重复元素时,证明有环,而且必定时入环的入口。
方法二:快慢指针
定义快慢指针,快指针速度时慢指针的一倍,也就是slow * 2 = fast,这里fast和slow分别代表当快慢指针走过的距离,在b点相遇时,slow = a + b,fast = a +n(b+c)+b,这里n代表快指针在环里循环的次数,结合两条式子得出,a=c+(n−1)(b+c),当n = 1时,快慢指针第一次相遇,a = c。
public ListNode detectCycle(ListNode head) {
if (head == null) {
return null;
}
ListNode slow = head, fast = head;
while (fast != null) {
slow = slow.next;
if (fast.next != null) {
fast = fast.next.next;
} else {
return null;
}
if (fast == slow) {
ListNode ptr = head;
while (ptr != slow) {
ptr = ptr.next;
slow = slow.next;
}
return ptr;
}
}
return null;
}
复杂度分析
-
时间复杂度:,没环的情况,遍历一次链表长度;有环,快慢指针相遇,慢指针还要多走
n距离,所以还是 -
空间复杂度:,常数空间。