欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

剑指offer 之 链表中环的入口节点

程序员文章站 2022-06-17 17:46:52
...

文章目录

题目

寻找链表中环的入口节点,如果有环返回入口节点,如果无环返回None。

思路

这道题分两步走:

  1. 判断链表是否有环: 两个指针,一快一慢,如果相遇了就说明有环,如果走到头了,就说明没环。很像小学的追及问题哈。
  2. 寻找环的入口节点: 这里有一种比较容易想到的方法就是我们再定义一个新的指针,从相遇的节点出发等到它回来,就可以知道环的长度m,然后再用两个指针从头节点出发,一个先走m步,然后两个指针再一起走,相遇的地方就是入口节点。
    不过除了这种方法还有一种更简单的方法:定义两个节点,一个从第一步相遇的节点出发,另一个从头出发,它俩相遇的位置就是环的入口节点。推导见下图:
    剑指offer 之 链表中环的入口节点

代码

class ListNode:
    def __init__(self, val):
        self.val = val
        self.next = None

class Solution:
    '''
    判断一个链表是否有环,如果有,返回环的入口节点;如果没有,返回None
    '''

    def getMeetNode(self, pHead):
        if not pHead:
            return None
        pQuick = pSlow = pHead
        while pQuick and pQuick.next:
            pQuick = pQuick.next.next
            pSlow = pSlow.next
            if pQuick == pSlow:
                return pQuick
        return None

    def entryOfLoop(self, pHead):
        '''
        两步走:
        1. 两个指针一块一满,判断是否有环,相遇则有环,到头则无环
        2. 两个指针,一个从相遇的节点出发,另一个从头出发,它们相遇时的节点就是环的入口节点
        '''
        pMeet = self.getMeetNode(pHead)
        if not pMeet:
            return None
        pNew = pHead
        while pNew != pMeet:
            pNew = pNew.next
            pMeet = pMeet.next
        return pNew

if __name__ == '__main__':
    solution = Solution()
    data = [1, 2, 3, 4, 5, 6]

    #============= case1 有环链表 ==============#
    pHead1 = ListNode(0)
    pCur = pHead1
    for num in data:
        pCur.next = ListNode(num)
        pCur = pCur.next
        if num == 3:
            pMeet = pCur
    pCur.next = pMeet

    #============= case2 无环链表 ==============#
    pHead2 = ListNode(0)
    pCur = pHead2
    for num in data:
        pCur.next = ListNode(num)
        pCur = pCur.next
    
    pEntry1 = solution.entryOfLoop(pHead1)
    pEntry2 = solution.entryOfLoop(pHead2)
    assert(pEntry1.val == 3)
    assert(pEntry2 is None)
    print("Congratulations!")
相关标签: 剑指offer