问题说明
编写一个程序,找到两个单链表相交的起始节点。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路与注意
官方文档描述is
为对象标示符(object identity),而==表示的是相等。is的作用是用来检查对象的标示符是否一致,也就是两个对象在内存中的位置是否一样,而==
是用来检查两个对象是否相等
因为是找到相同的元素(id相同)所以之前的比较我用的是 is
而不是 ==
但这里可以用 ==
,和id
结果一样。
参考Leetcode中的答案:
- 找到长度差
- 指针追逐
- 使用集合
找到长度差
class Solution():
def getIntersectionNode(self, headA, headB):
"""
:param headA: ListNode
:param headB: ListNode
:return: ListNode
"""
a = b = 0
h1 = headA
h2 = headB
while h1:
h1 = h1.next
a +=1
while h2:
h2 = h2.next
b +=1
h1 = headA
h2 = headB
if a >= b:
for i in range(a - b):
h1 = h1.next
else:
for i in range(b - a):
h2 = h2.next
while h1 and h2:
if h1 is h2:
break
h1 = h1.next
h2 = h2.next
return h1
指针追逐
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
将两个链表拼接在一起,p是headA->headB
q是headB->headA
这样p和q的长度一致,会在相交节点相遇
要么就都返回None
:param headA: ListNode
:param headB: ListNode
:return: ListNode
"""
p = headA
q = headB
# p 4,1,8,4,5->5,0,1,8,4,5
# q 5,0,1,8,4,5->4,1,8,4,5
while p is not q:
p = p.next if p else headB
q = q.next if q else headA
return p
使用集合
class Solution():
def getIntersectionNode(self, headA, headB):
"""
:param headA: ListNode
:param headB: ListNode
:return: ListNode
"""
s = set()
h1 = headA
h2 = headB
while h1:
s.add(h1)
h1 = h1.next
while h2:
if h2 in s:
break
h2 = h2.next
return h2
总结
上面三种方法的时间复杂度逐渐降低
可供测试用的源代码
"""
160. 相交链表
编写一个程序,找到两个单链表相交的起始节点。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
"""
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
## 指针追逐
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
将两个链表拼接在一起,p是headA->headB
q是headB->headA
这样p和q的长度一致,会在相交节点相遇
要么就都返回None
:param headA: ListNode
:param headB: ListNode
:return: ListNode
"""
p = headA
q = headB
# p 4,1,8,4,5->5,0,1,8,4,5
# q 5,0,1,8,4,5->4,1,8,4,5
while p is not q:
p = p.next if p else headB
q = q.next if q else headA
return p
## 因为是找到相同的元素(id相同)所以之前的比较我用的是 is 而不是 ==
## 但这里可以用 ==
# 官方文档描述is为对象标示符(object identity),而==表示的是相等。is的作用是用来检查对象的标示符是否一致,也就是两个对象在内存中的位置是否一样,而==是用来检查两个对象是否相等。
## 用集合set
# class Solution():
# def getIntersectionNode(self, headA, headB):
# """
#
# :param headA: ListNode
# :param headB: ListNode
# :return: ListNode
# """
# s = set()
# h1 = headA
# h2 = headB
# while h1:
# s.add(h1)
# h1 = h1.next
# while h2:
# if h2 in s:
# break
# h2 = h2.next
# return h2
## 距离,容易想到
# class Solution():
# def getIntersectionNode(self, headA, headB):
# """
#
# :param headA: ListNode
# :param headB: ListNode
# :return: ListNode
# """
# a = b = 0
# h1 = headA
# h2 = headB
# while h1:
# h1 = h1.next
# a +=1
# while h2:
# h2 = h2.next
# b +=1
# h1 = headA
# h2 = headB
# if a >= b:
# for i in range(a - b):
# h1 = h1.next
# else:
# for i in range(b - a):
# h2 = h2.next
# while h1 and h2:
# if h1 is h2:
# break
# h1 = h1.next
# h2 = h2.next
# return h1
def stringToInt(input):
return int(input)
def stringToListNode(intersectVal, listA, listB, skipA, skipB):
# Generate list from the input
# Now convert that list into linked list
"""
:param intersectVal: int intersection node (0 means no intersection between A and B)
:param listA: list contains the value of a singly-linked list A
:param listB: list contains the value of a singly-linked list B
:param skipA: int the number of nodes [start node, intersection node) in A
:param skipB: int the number of nodes [start node, intersection node) in B
:return: tuple contains two singly-linked lists
"""
dummyRoot1 = ListNode(0)
ptr1 = dummyRoot1
dummyRoot2 = ListNode(0)
ptr2 = dummyRoot2
# d1 = (dummyRoot1==dummyRoot2)
# d2 = dummyRoot1 is dummyRoot2
a = b = 0
for number in listA:
ptr1.next = ListNode(number)
ptr1 = ptr1.next
a += 1
if a == skipA:
break
for number in listB:
ptr2.next = ListNode(number)
ptr2 = ptr2.next
b += 1
if b == skipB:
break
intersec = ptr1
if intersectVal == 0:
for i in range(a, len(listA)):
ptr1.next = ListNode(listA[i])
ptr1 = ptr1.next
for i in range(b, len(listB)):
ptr2.next = ListNode(listB[i])
ptr2 = ptr2.next
else:
for i in range(a, len(listA)):
ptr1.next = ptr2.next = ListNode(listA[i])
ptr1, ptr2 = ptr1.next, ptr2.next
return dummyRoot1.next, dummyRoot2.next, intersec.next
def listNodeToString(node):
if not node:
return "[]"
result = ""
while node:
result += str(node.val) + ", "
node = node.next
return "[" + result[:-2] + "]"
def main():
line1 = 8
intersectVal = stringToInt(line1)
listA = [4,1,8,4,5]
listB = [5,0,1,8,4,5]
line3 = 2
skipA = stringToInt(line3)
line4 = 3
skipB = stringToInt(line4)
headA, headB, intersec =stringToListNode(intersectVal, listA, listB, skipA, skipB)
ret = Solution().getIntersectionNode(headA, headB)
out = listNodeToString(ret)
if intersectVal>0 and ret is intersec:
print("Intersected at \'%d\'" % intersectVal)
elif intersectVal==0 and not ret:
print("No intersection")
else:
print("Wrong output")
print(out)
if __name__ == '__main__':
main()