当前位置:   article > 正文

链表中环的入口节点_环形链表入口

环形链表入口

链表中环的入口节点

题目描述:如果一个链表中包含环,如何找出环的入口节点?如图所示,环的入口节点是节点3。
示例图
首先第一步,我们应该确定链表中是否包含环。可以使用快慢指针来解决这个问题,定义两个指针,同时从链表的头节点出发,快指针一次走两步,慢指针一次走一步,如果快指针走到了链表的末尾(NULL)说明链表是无环的,因为如果有环的话最后的结点不会是NULL而是环的开始。如果快指针追上慢指针,说明链表有环。
这里如果链表有环,快指针一定是能够追到慢指针的。假设快指针走后,距离慢指针距离为n,那么因为链表有环(可以理解为操场跑圈),快指针每走一步会经过两个节点,而慢指针只会经过一个节点,因此快指针每走一步与慢指针的距离都会-1,最终的距离为 n − 1 , n − 2 , ⋯   , 2 , 1 , 0 n-1,n-2,\cdots,2,1,0 n1,n2,,2,1,0。因为距离每次会减一,所以最终会到0,即二者相遇。
然后就是要找到环的入口。这里还是用两个指针来解决问题。我们首先思考一下,如果链表的总长度为n,那么指向链表头节点的指针走过n-1步就到达链表的末尾(以上图为例,从1号节点出发,走5步可以到6号节点)那么再走一步就到达了环的开头,即3号节点。也就是说头指针走n步可以到达环的入口。
我们假设在环开头前的结点数量为x,环中的结点数量为y,那么有 n = x + y n=x+y n=x+y,即6=2+4。假设有两个指针 p 1 , p 2 p_1,p_2 p1,p2指向头节点, p 1 p_1 p1先走 y y y步,到达节点5,距离走到环的开头还需走 n − y = x n-y=x ny=x步,也就是再走2步。如果此时 p 2 p_2 p2从头节点出发,那么再走 x x x步即可和 p 1 p_1 p1相遇。因此,我们可以先让 p 1 p_1 p1先走 y y y步,然后 p 2 p_2 p2 p 1 p_1 p1同时移动,相遇时一定是环的入口节点,并且同时移动的距离为 x x x
这里之所以这么做而不是直接让 p 1 p_1 p1 p 2 p_2 p2直接向前走 x x x步,是因为代码实现时计算 x x x并不方便,因为想要计算 x x x,需要知道环的入口节点在哪,而我们的目标就是求环的入口节点,因此求 x x x没有意义。而计算 y y y更方便,因此实际上并不知道 x x x的大小,当然也不知道 n n n的大小。前面只是为了好分析将 n n n x x x实际大小写了出来,实际代码实现只有 y y y
此时我们的思路已经明确了,我们需要做三件事:(1)通过快慢指针来判断链表是否有环;(2)计算出环中的结点;(3)定义两个指针,其中一个指针先走“环中结点数量”步,然后第二个指针和第一个指针同时移动,相遇时即是环的入口位置。
在LeetCode提交代码如下所示:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 通过快慢指针判断链表是否有环
    def isCircle(self,head):
        if (head == None):
            return False
        # 定义快慢指针
        fast_pointer = head
        slow_pointer = head
        # 如果链表只有一个节点,说明没有环
        if(slow_pointer.next == None):
            return False
        
        while(fast_pointer != None):
            slow_pointer = slow_pointer.next
            fast_pointer = fast_pointer.next
            if(fast_pointer == None):
                return False
            fast_pointer = fast_pointer.next
            if(slow_pointer == fast_pointer):
                return slow_pointer
        return False

    # 判断环中节点的数量
    def circleNum(self,node):
        temp_node = node
        node = node.next
        count = 1
        while(node != temp_node):
            count += 1
            node = node.next
        return count
            
        


    def detectCycle(self, head: ListNode) -> ListNode:
        circle_node = self.isCircle(head)
        if(circle_node == False):
            return None
        else:
            circle_num = self.circleNum(circle_node)
            p_1 = head
            p_2 = head
            # p_1先走circle_num步
            for i in range(circle_num):
                p_1 = p_1.next
            while(p_1 != p_2):
                p_1 = p_1.next
                p_2 = p_2.next
            return p_1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

运行结果如下所示:
运行结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/604764
推荐阅读
相关标签
  

闽ICP备14008679号