链表的结构看似简单,实则隐藏着诸多复杂的问题等待我们去挖掘。其中,环形链表的判定与处理便是一道颇具难度的关卡。如何准确判断一个链表是否存在环?若存在环,又该如何找到环的入口节点?
首先介绍一个概念,快慢指针: 什么是快慢指针呢?顾名思义就是一个指针走的快一点一个指针走的慢一点。
请看例题:
给你一个链表,让你返回一个中间节点。 leetcode.cn/problems/mi…
解决方法这个时候,你定义一个快指针指向头节点,定义一个慢指针指向头节点,快指针一次走两个,慢指针一次走一个。当快指针遍历完成之后,慢指针是不是刚好遍历一半,所以慢指针就是答案。但是,在链表长度奇偶性不一样时,又要分类讨论。链表长度为奇数时,假设链表为123,中间节点为2,慢指针指向2时快指针指向3(最后一个节点),当链表长度为奇数时,假设为1234,中间节点为3,当慢指针指向3时,快指针指向4的下一个节点为空。所以循环条件就是当快指针不为空且快指针的下一个节点不为空while fast and fast.next
代码实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow=head
fast=head
while fast and fast.next:
slow=slow.next
fast=fast.next.next
return slow
但是快慢指针的运用还远不止这些
请看下一题:
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
分析:这道题同样用快慢指针做,假设没环,慢指针是不可能追上快指针的,假设有环,就像操场一样,快指针跑完一圈了,会与慢指针相遇(俗称套圈)这样,假如在循环过程中,快指针与慢指针相遇了,那么就说明有环。
代码实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
fast=head
slow=head
while fast and fast.next:
fast=fast.next.next
slow=slow.next
if fast is slow:
return True
return
仅此而已吗? nonono
如果再让你找到环的入口呢?
下一道例题:
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
分析 如图
设头节点到入口的距离为a
入口到相遇点的距离为b
相遇点到入口的距离为c
环长为b+c
慢指针距离=a+b+K1(b+c)
快指针距离=a+b+K2(b+c)
慢的距离的两倍等于快的距离
2[a+b+K1(b+c)]=a+b+K2(b+c)
化简得 a-c=(k2-1-2k1)(b+c)
这个等式意味着慢指针在相遇后继续走到入口,一个指针(head)在头节点也同时往后走,最后它俩相遇一定在入口
代码实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
fast=head
slow=head
while fast and fast.next:
fast=fast.next.next
slow=slow.next
if fast is slow:
while head is not slow:
head=head.next
slow=slow.next
return slow
return None
好了,具体的应用还是得到实际题目中(完结)