判断两个无环单链表是否交叉
题目描述:
如上图,这两个链表相交于结点5,要求判断两个链表是否相交,如果相交,找出相交处的结点。
解题思路:
方法一:Hash 法
如上图所示,如果两个链表相交,那么它们一定会有公共的结点,由于结点的地址或引用可以作为结点的唯一标识,因此,可以通过判断两个链表中的结点是否有相同的地址或引用来判断链表是否相交。
方法二:首尾相接法
将这两个链表首尾相连(例如把链表headl尾结点链接到head2的头指针),然后检测这个链表是否存在环,如果存在,则两个链表相交,而环入口结点即为相交的结点。
方法三:尾结点法
如果两个链表相交,那么两个链表从相交点到链表结束都是相同的结点,必然是Y字形,所以,判断两个链表的最后一个结点是不是相同即可。即先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两个链表相交,这时记下两个链衰的长度c1,c2,再遍历一次,长链表结点先出发前进|c1-c2|步,之后两个链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。
代码实现:
# -*-coding:utf-8-*-
"""
@Author : 图南
@Software: PyCharm
@Time : 2019/9/7 21:24
"""
# 尾节点法
class Node:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def printLink(head):
if head is None or head.next is None:
return
cur = head.next
while cur is not None:
print(cur.data, end=' ')
cur = cur.next
print()
# 构造相交链表
def conInterLink(n1, n2, k):
k = int(k)
nums1 = list(map(int, n1.split(' ')))
nums2 = list(map(int, n2.split(' ')))
if len(nums1) > len(nums2):
return conLink(nums1, nums2, k)
else:
head2, head1 = conLink(nums2, nums1, k)
return head1, head2
def conLink(nums1, nums2, k):
head1 = Node()
head2 = Node()
cur1 = head1
cur2 = head2
f = None
for i in range(1, len(nums1) + 1):
node = Node(nums1[i - 1])
cur1.next = node
cur1 = node
if i == k:
f = cur1
for i in range(1, len(nums2) + 1):
node = Node(nums2[i - 1])
cur2.next = node
cur2 = node
cur2.next = f
return head1, head2
# 遍历两个链表并计算长度
def traLink(head):
cur = head.next
count = 1
while cur.next is not None:
cur = cur.next
count += 1
return cur, count
# 长链表先走k步
def beforLink(head, k):
cur = head.next
for i in range(k):
cur = cur.next
return cur
# 获取相交点
def getPoint(head1, head2, count1, count2):
cur1 = beforLink(head1, count1 - count2)
cur2 = head2.next
while cur1 is not None:
if cur1 is cur2:
return cur1.data
cur1 = cur1.next
cur2 = cur2.next
def findInterPoint(head1, head2):
cur1, count1 = traLink(head1)
cur2, count2 = traLink(head2)
if cur1 is cur2:
print("两个链表相交!")
if count1 > count2:
return getPoint(head1, head2, count1, count2)
else:
return getPoint(head2, head1, count2, count1)
else:
return "两个链表不相交!"
if __name__ == '__main__':
n1 = input('Link1:')
n2 = input('Link2:')
k = input('相交点:')
head1, head2 = conInterLink(n1, n2, k)
printLink(head1)
printLink(head2)
print(findInterPoint(head1, head2))
运行结果:
链表一长度大于链表二:
链表二长度大于链表一:
两链表不相交:
两链表相交在第一个节点:
引申:如果单链表有环,如何判断两个链表是否相交
- 如果一个单链表有环,另外一个没环,那么它们肯定不相交。
- 如果两个单链表都有环并且相交,那么这两个链表一定共享这个环。如下图
- 判断两个有环的链表是否相交的方法为:首先找到链表headl中环的入口点pl,然后遍历链表head2,判断链表中是否包含结点 pl,如果包含,则这两个链表相交,否则不相交。
- 找相交点的方法为:把结点pl看作两个链表的尾结点,这样就可以把问题转换为求两个无环链表相交点的问题。