单链表环的判断及入口结点的查找之快慢指针及其python实现
快慢指针
定义:
快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
一定会相遇的证明
1、如果链表没有环,那么快指针比慢指针先到达尾部(null)。
2、如果链表有环的话,因为快指针走的比慢指针快,所以在环中相遇的过程可以看作是快指针从环后边追赶慢指针的过程。
用递归法证明,快慢指针一定会相遇:
(1)快指针与慢指针之间差一步。此时继续往后走,慢指针前进一步,快指针前进两步,两者相遇。
(2)快指针与慢指针之间差两步。此时继续往后走,慢指针前进一步,快指针前进两步,两者之间相差一步,转化为第一种情况。
(3)快指针与慢指针之间差N步。此时继续往后走,慢指针前进一步,快指针前进两步,两者之间相差(N+1-2)即N-1步。重复这个过程,直到快指针和慢指针相遇。
因此,此题得证。所以快指针必然与慢指针相遇。
带环链表
链表中有循环的部分,通俗的说就是没有尾节点
判断单链表是否存在环
让快慢指针从链表头开始遍历,快指针向前移动两个位置,慢指针向前移动一个位置;如果快指针到达NULL,说明链表以NULL为结尾,不是循环链表。如果 快指针追上慢指针,则表示出现了循环。
对于此问题可以考虑跑道的问题,如果是直线型的跑道,无论如何快慢指针都不会相遇;如果是环形跑道(无论跑道都是环还是先有一段直线,再有环),快慢指针必定会相遇(前文已证)。
符号约定:链表头到环入口的距离为p,环的长度为l,环入口到指针第一次相遇点的距离为c
假设第一次相遇时快慢指针走了n步,则
第一次相遇时fast指针走过的距离为
第一次相遇时slow指针走过的距离为
环入口的求法:
相遇时让fast指针从链表头重新开始走,且步长变为1,slow指针继续从相遇点走,步长仍为1,则再次相遇时
slow指针走过的距离为
fast指针走过的距离为
得到,也就是说再次相遇时是在入口处。
采用python实现过程如下:
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
#链表空或者有一个、两个结点均形不成循环链表,故直接判断
if pHead==None or pHead.next==None or pHead.next.next==None:
return None
#指定快、慢指针
fast = pHead.next.next
slow = pHead.next
#先判断有无环
while fast!=slow:
if fast.next!=None and fast.next.next!=None:
fast=fast.next.next
slow=slow.next
else:
return None
#跳出循环说明有环,此时fast==slow
fast = pHead
while fast!=slow:
fast=fast.next
slow=slow.next
return slow
上一篇: LeetCode0141. 环形链表