力扣题目:环形链表及环形链表II
开篇
今天是备战蓝桥杯的第26天和算法村开营第4天。挑选了链表的黄金关卡与大家分享。
题目一:环形链表
题目链接: 141.环形链表
题目描述
方法一、哈希表
判断是否有环,可以利用哈希表,遍历的时候把节点放进去。当有节点在哈希表出现过时,证明存在环
public ListNode detectCycle(ListNode head){
ListNode pos = head;
Set<ListNode>visited = new HashSet<>();
while (pos =! null){
if (visited.contains(pos)) return pos;
else visited.add(pos);
pos pos.next;
}
return null;
}
方法二、快慢指针
如果只用O(1)的空间,有没有其他方法?
快慢指针!这是判断是否有环最有效的方法。慢指针一次走一步,快指针一次走两步。如果快指针能走到表尾,则没有环。否则,快慢指针在环中绕圈的时候总会碰到一起。两者相碰作为判定存在环的条件
public boolean hasCycle(ListNode head){
if (head == null || head.next == null) return false;
ListNode fast = head, slow = head;
while(fast != null & fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast==slow)
return true;
}
return false;
}
题目二:环形链表II
题目链接: 142.环形链表II
与上一题只有返回的内容不同
方法一、哈希表
可以利用哈希表,遍历的时候把节点放进去。当有节点在哈希表出现过时,该结点就是环的入口
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode node =head;
Set<ListNode> set = new HashSet();
while(node != null){
if(set.contains(node)) return node;
set.add(node);
node = node.next;
}
return null;
}
}
方法二、快慢指针(重点)
这里的问题是如果知道了一定有入口,那么如何确定入口的位置呢?方法非常简单,但是要理解清楚有些难度。
结论:先按照上面快慢方式寻找到相遇的位置(假设如下图中Z),然后将两指针分别放在链表头(X)和相遇位置(Z),并改为相同速度推进,则两
指针在环开始位置相遇(Y)
推导过程
1.假设一圈就遇到:
为了便于理解,我们首先假定快指针在第二次进入环的时候就相遇了.
此时的过程是:
(1)找环中相汇点。分别用fast、slow表示快慢指针,slow每次走一步,fast就走两步,直到在环中的某个位置相会,假如是图中的Z。
(2)第一次相遇:
那么我们可以知道fast指针走了a+b+c+b步,
slow指针走了a+b步
那么:2*(a+b)=a+b+c+b
所以a=c因此此时让slow从Z继续向前走,fast回到起点,两个同时开始走(两个每次都走一步),一次走一步那么它们最终会相遇在y点,正是环的起始点。
2.如果多圈后相遇
设链表中环外部分的长度为a,slow指针进入环后,又走了b的距离与fast相遇。此时,fast指针已经走完了环的n圈,因此它走过的总距离为:
Fast:a+n(b+c)+b=a+(n+1)b+nc
根据题意,任意时刻,fast指针走过的距离都为slow指针的2倍。因
此,我们有:
a+(n+1)b+nc=2(a+b)
由于b+c就是环的长度,假如为len,则:
a=c+(n-1)*len
这说明什么呢?说明相遇的时候快指针在环里已经转了(n-1)圈,如果
n==1就退化成了我们上面说的一圈的场景。假如n是2,3,4呢,这只
是说明当一个指针p1重新开始从head走的时候,另一个指针p2从Z点开
始,p1、p2共速时,两者会恰好在入口处相遇,只不过p2要先在环中转n-1圈。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while(fast != null && fast.next != null){
if(slow.next == fast.next.next) break;
slow = slow.next;
fast = fast.next.next;
}
if(fast == null || fast.next == null) return null;
ListNode node1 = head, node2 = slow.next;
while(node1 != node2){
node1 = node1.next;
node2 = node2.next;
}
return node1;
}
}
结语
如果对这道题分享对您有所帮助,点个关注,为会每天更新力扣题的分享,与大伙儿一起进步!