链表是否含环以及确定环的起点
环形链表是什么?
链表的最后一个节点的next域不是null,而是指向链表头
确定链表是否含环
在运动场上跑步的时候,从同一起点同时出发跑的快的人最终一定会超过跑的慢的人一圈又从后面又再次相遇,判断链表是否含环采用的就是这种思想
这时候就需要快慢指针就相当操场上跑步的两个人一个跑的快一个跑的慢
fast = fast.next.next;快指针一次走两步
slow = slow.next;慢指针一次只走一步
两个指针从头节点同时出发
- 在含有环的情况下快慢指针最终一定会再次指向同一个节点
- 不含有环的情况下快指针肯定会先走到链表的结尾
以上就是判断链表是否含环的思路
代码实现如下:
public boolean hasCycle(ListNode head) {
// 快慢指针
ListNode fast = head;
ListNode slow = head;
/**
* 当快指针还没走到链表尾或快慢指针还没相遇的时候需要继续前进
* 判断条件因为快指针一次走两步 为避免空指针异常则fast!=null,fast.next!=null;
*/
while(fast!=null&&fast.next!=null){
// 快指针一次走两步
fast = fast.next.next;
// 慢指针一次走一步
slow = slow.next;
// 快慢指针相遇,则链表含环
if(fast==slow){
return true;
}
}
return false;
}
确定环的起点
图解(字写的不好看也要仔细看呀 看了就懂了)
通过图解我们知道从链表的头节点到环的起点的距离等于从快慢指针相遇点到环起点的距离
此时只需要将快指针或者慢指针放回链表的起点,然后快慢指针再同时以相同的速度(一次都只走一步)出发,因为链表的头节点到环的起点的距离等于从快慢指针相遇点到环起点的距离所以再次相遇点就是环的起点
代码实现:
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast!=null&&fast.next!=null){
fast = fast.next.next;
slow = slow.next;
// 证明含环 则跳出循环继续查找环起点
if(fast==slow){
break;
}
}
// fast或者fast.next走到了链表尾 证明链表无环 则退出函数不继续进行查找环起点
if(fast==null||fast.next==null){
return null;
}
// 将慢指针放回链表头
slow = head;
// 一直循环直到相遇
while(slow!=fast){
// 以相同的速度前进
slow = slow.next;
fast = fast.next;
}
return slow;
}
查找环起点问题的核心就是从链表的头节点到环的起点的距离等于从快慢指针相遇点到环起点的距离!!!