有环单链表,求环长、链长;求两链表的交点

有环单链表,求环长、链长

这是一个关于单链表的经典例题。即,给定一个有环的单链表,求环长、链长等。或者,给定一个单链表,判断是否有环?

可以遍历这个链表,将每一个节点存入一个有顺序的集合,同时判断当前节点是否在这个集合中出现,从而判断该链表是否有环以及求环长与链长。当时空间复杂度与时间复杂度都过大了。

另一个经典方法就是快慢指针,即两个指针同时从链表头开始走,快指针一次走2步,慢指针一次走1步。于是
有环单链表,求环长、链长;求两链表的交点_第1张图片
假设这个有环链表的join点之前的节点数为a,环长为n,两个指针相遇点距离表头距离为a+b。如上图,其中k表示快慢指针相遇的时候,快指针走过环的圈数。

那么,让快慢指针同时从表头出发,当它们相遇的时候,让慢指针回到表头,并让快指针的步长变为1。等到它们再次相遇的时候,相遇点即为链表环的join点。

原因如上图,快指针再走a个节点(此时每步走一个节点)就会到达join点,慢指针从表头开始走a个节点也会到达join点。

这样即可判断给定单链表是否有环。也能求解环长以及链长。

代码如下:

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

def buildRingedLinkList(handleLen, ringLen):
    head = Node(0)
    temp = head
    for i in range(1, handleLen+1):
        temp.next = Node(i)
        temp = temp.next
    join = temp
    for i in range(handleLen+1, handleLen+ringLen):
        temp.next = Node(i)
        temp = temp.next
    temp.next = join
    return head

def getJoinNode(linkList):
    l1, l2 = linkList, linkList
    while True:
        if l2 is None:
            return None
        l1 = l1.next
        l2 = l2.next.next
        if l1 == l2:
            break
    l1 = linkList
    while True:
        l1 = l1.next
        l2 = l2.next
        if l1 == l2:
            break
    return l1

head = buildRingedLinkList(3, 5)
print(getJoinNode(head).val)

代码中,buildRingedLinkList方法用于构造有环单链表(代码中构造的有环单链表如下图),getJoinNode用于获取有环单链表的join点,如果无环则返回None。

有环单链表,求环长、链长;求两链表的交点_第2张图片

求两链表的交点

对于两个链表存在一个交点的情况,即类似于“Y”形状的链表,求这个交点。

方法一:我们可以直接让其中一个链表首尾相连,即将这两个有交点的链表转化为有环单链表。于是可以直接采用求解有环单链表的解法求解。

方法二:首先分别遍历获得两个链表的长度,让指针 l 1 l1 l1在较长的链表上先走两个链表长度之差个节点,然后让指针 l 2 l2 l2在较短的链表上与指针 l 1 l1 l1同时走,并判断两个指针所指是否相同,若相同则找到了交点直接返回即可。

你可能感兴趣的:(这是基础)