环形链表
问题描述
给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。详见leetcode141
问题分析
最直接的方式就是利用集合来判断,遍历链表节点,判断该节点是否存在于集合中,如果存在,则说明链表中存在环,如不存在,继续遍历,如果遍历结束后仍未发现当前遍历节点存在于集合中,则链表中不存在环。
上面提到的方式简单直接,但是在面试中一般不允许使用has或者集合的方式。除此之外,我们可以考虑双指针,如果链表中存在环,则快慢指针,一定会相遇,我们假设fast指针每次走两步,slow指针每次走一步,当fast指针即将追上slow指针时,存在两种情况,fast指针与slow指针相差两步或者相差一步,当相差一步时,下一次fast指针走两步,slow指针走一步,相遇,当相差两步时,下一次slow指针走一步,fast指针走两步,变成相差一步的情况,综上,只要链表中存在环,slow指针和fast指针一定会相遇。
代码实现
使用集合实现
public boolean hasCycle ( ListNode head) { ListNode current = head; Set < ListNode > set = new HashSet < > ( ) ; while ( current!= null ) { if ( set. contains ( current) ) { return true ; } else { set. add ( current) ; } current = current. next; } return false ;
}
使用双指针实现
public boolean hasCycle ( ListNode head) { 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 ;
}
环形链表 II
问题描述
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。详见leetcode142
问题分析
找环的入口比较复杂,可以结合下图进行理解。假设链表中存在环,非环长度为a,环长度为b,则使用快慢指针一定会相遇。我们分析相遇时的情况。fast指针式slow指针速度的两倍,则f=2s,fast比slow指针多走了n个环的长度,f=s+nb,联立方程,得f=2nb,s=nb,当s走到环的入口时,s = a+nb,我们想要找到环的入口,只需要让slow指针在走a步,如何确定a的值呢,我们仍然使用双指针来实现。让fast指针指向head,每次走一步,slow与fast同步走,两者在一起走a步,在环入口相遇
代码实现
public ListNode detectCycle ( ListNode head) { ListNode slow = head; ListNode fast = head; while ( fast!= null && fast. next!= null ) { fast= fast. next. next; slow = slow. next; if ( fast== slow) { break ; } } if ( fast== null || fast. next== null ) { return null ; } fast = head; while ( fast!= slow) { fast = fast. next; slow = slow. next; } return slow;
}
总结
链表没有下标,所以只能靠指针遍历的方式操作元素,但是一个指针在链表有环的前提下无法确定终止条件,所以,我们使用双指针来解决链表环的问题,常见环的问题就是判断是否有环和找到环的入口,上面的思路可能比较复杂,可以结合图示来理解。