Given a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
判断链表是否有环,具体分析过程可以看这篇博客,主要分析了3种方法,两种常规,一种比较巧妙。
总结一下,前两种主要是在遍历到某一节点时,对当前以及之前遍历过的节点进行检查,若发现有重复的,则说明有环。既可以浪费时间直接对当前节点之前的列表进行遍历,优点是无需另外开辟空间;也可以用一个哈希链表以节点为键值来存储遍历过的节点,访问节点时,到哈希中发现是否存在,若有,则存在环,否则将当前节点存进哈希表,这种的优点是时间上大大加快。
巧妙一点的方法:定义两个指针在一开始都指向头节点,然后设定在每一次循环里,让快的指针移动两位,慢的指针移动一位。
假如存在环,快的指针总有机会与慢的指针重合。
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null) return false;
ListNode fast=head;
ListNode slow=head;
while(fast.next != null && fast.next.next != null){//这里很容易发生越界,坑的是我把两个.next写在了前面就会越界,写在后面就不会
fast=fast.next.next;
slow=slow.next;
if(fast == slow){
return true;
}
}
return false;
}
}
判断环的入口
一开始我傻了地以为,只要上面相遇那点就是环的入口,这个很明显就是不对的,但是我们依然可以在上面的基础上进行改进。在上面,我们可以获得相交的一点是位于环内的,那么为了求环的入口,不就是求链表与环的交点?
有了这个想法,我们可以再定义两个指针,一个指向头节点表示原链表,一个指向刚才相遇的环内的节点,当它们相等时,返回的就是环的入口。这篇博客也讲得很清楚
public class Solution {
ListNode EntryNodeOfLoop(ListNode h){
if(h == null || h.next == null)
return null;
ListNode slow = h;
ListNode fast = h;
while(fast != null && fast.next != null ){
slow = slow.next;
fast = fast.next.next;
if(slow == fast){
ListNode p=h;
ListNode q=slow;//相当于让q指向了m1
while(p != q){
p = p.next;
q = q.next;
}
if(p == q)
return q;
}
}
return null;
}