分享2道leetcode题目(判断链表是否有环以及找出环的入口点)
141. Linked List Cycle
Given a linked list, determine if it has a cycle in it.
142. Linked List Cycle II
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
第一题就是给你一个链表,让你判断是否有环,如果有返回true,否则返回false
解法过程
1.首先说明链表环的构成:
链表的某个节点的next指针指向到前面的节点,如以下所示
(0->1->2->3->4->5->6->3->4…)
这样子在6节点的后面就会形成无穷无尽的链表,就形成环了。
2.设置分别设置一个快慢指针,快指针运行速度是慢指针的2倍,如果该链表是个环,则快慢指针必相遇,并且相遇是慢指针并没有跑完整个链表长度
快指针设置fast = fast.next.next;
慢指针设置slow = slow.next;
public boolean hasCycle(ListNode head) {
if(head == null || (head.next == null)) {
return false;
}
ListNode slow = head;
ListNode fast = head;
//如果快慢指针相遇,则存在环
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(fast == slow) {
return true;
}
}
return false;
}
第二题就是给你一个链表,如果这个链表有环,则返回环的入口点,如果没有返回null
解法过程
先列出一个有环的链表:
1->2->3->4->5->6->7->8->9->10->3->4…
那答案就是这个链表返回3这个节点
1.顺着第一步分析,快慢指针相遇点是在9这个节点,如果这时候在9这处放置一个指针,在头节点处放置一个指针,让他们同时以相同的速度移动,则很恰巧他们是在3这个环的入口点相遇,这是巧合吗。接下来就要验证该方法是否可行。
设置链表长度为L,入口点距离头节点距离为a,快慢指针相遇点距离入口点为b,满指针速度为s,环的长度为r,则可以得到以下公式:
2s = s + nr (n为环的圈数)
s = a + b (慢指针从头节点走到相遇点)
r = L - a
2.则我们可以把公式变形成如下
a + b = nr
a = nr -b
a = (n-1)r + r - b
a = (n-1)r + (L -a -b)
这个公式可以得出a就是环入口距离头节点的距离,(n-1)r是(n-1)圈的环,(L-a-b)其实就是相遇点到环入口的距离
那其实可以得出如果一个指针从相遇点出发,则一定会跟一个从头指针出发的指针相遇,并且相遇点 就是环的入口点
3.那么解法就很简单了
public ListNode detectCycle(ListNode head) {
if(head == null || (head.next == null)) {
return null;
}
ListNode slow = head,fast = head;
ListNode start = head;
ListNode end = null;
//快慢指针找到相遇点
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(fast == slow) {
end = fast;
break;
}
}
if(end == null || end.next == null ){
return null;
}
//这时重新在相遇点跟head出设置指针,然后同时走一步,则相遇点就是环入口
while(start != end) {
start = start.next;
end = end.next;
}
return start;
}
谢谢欣赏!