1.如何确定链表中是否有环
LeetCode 142题:环形链表 II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
- 1.1 Hash表
想要去判断有环,最简单的就是通过Hash,先遍历所有节点并存入hashmap中,如果存在环,那么出现相同节点时,这个节点就是环的入口
public ListNode detectCycle(ListNode head) {
ListNode cur = head;
Set<ListNode> map = new HashSet<ListNode>();
while(cur != null){
if(map.contains(cur)){
return cur;
}else{
map.add(cur);
}
cur = cur.next;
}
return null;
}
-
1.2 快慢指针
定义两个指针slow与fast,slow每次走1步fast每次走2步,如果存在环,那么最后fast一定会与slow相遇。
- 假如fast离slow之间有一个空格,如上图情况一所示,fast与slow下一步就共同到了3,就会相遇了。
- 假如fast离slow之间有两个空格,如上图情况二所示,fast下一步到3,slow下一步到4,就如情况一一样了。
public boolean hasCycle(ListNode head){
if (head == null || head.next == null) return false;
ListNode fast = head;
ListNode slow = head;
while(fast != null & fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast==slow)
return true;
}
return false;
}
2.如何确定链表中环的入口
同样可以使用hash表来解决,就是第一个出现相同节点时,这个节点即为环的入口。
当使用双指针来解决时,需要先通过快慢指针的方式找到slow与fast相遇的节点,再令p1从最开始出发,p2从相遇节点出发,两个指针以相同速度前进那么p1p2相遇的时候就为环的入口,具体原因看骨头哥的解析。
public ListNode detectCycle(ListNode head){
if(head == null){
return null;
}
ListNode slow = head,fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
if(fast.next != null){
fast = fast.next.next;
}else{
return null
}
if(slow == fast){
ListNode ptr = head;
while(ptr == slow){
slow = slow.next;
ptr = ptr.next;
}
return ptr;
}
}
return null;
}