题目
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例 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) 内存。
思路
这道题可以暴力搜索,也可以用哈希方法,但满足O(n)和O(1)的方法更佳。我自己没想到,看了Solution里的思路简直拍案叫绝。
设置两个指针pA和pB分别是headA和headB,分别让他们往后走,肯定有一个长一个短,有一个先走到头,假设是pA,那么都走到末尾pA比pB就少走几个节点,我们现在让pA指向headB继续走,pB走到末尾后指向headA继续走,如果有交点的话,pA和pB就一定会一起同时走到这个点,返回就可以了。
那么还有一些情况,比如两个一样长怎么办,我就多加了一个判断语句,判断第二个指针是否也在末尾。换头(pA指向headB)不应当直接链上,而应当赋值到开头节点,同时pB前进一步,否则改了第一个第二个就判断不了末尾了。对于两个单链表不想交的情况,我是判断他们末尾(abot,bbot)是否相等来实现,不等就说明到最后也没有相同的节点,那肯定是没交点了。最终时间超过70%已提交结果,空间超过90%已提交结果,具体实现如下:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
#headA, headB = headB, headA
pointerA = headA
pointerB = headB
if headA == headB:
return headA
if not headA or not headB:
return None
if not pointerA or not pointerB:
return None
while pointerA.next and pointerB.next:
pointerA, pointerB = pointerA.next, pointerB.next
if pointerA == pointerB:
return pointerA
if not pointerA.next:
abot = pointerA.val
if pointerB.next:
pointerB = pointerB.next
pointerA = headB
while pointerB.next:
pointerB = pointerB.next
pointerA = pointerA.next
bbot = pointerB.val
pointerB = headA
pointerA = pointerA.next
if abot != bbot:
return None
while True:
if pointerA == pointerB:
return pointerA
else:
pointerA = pointerA.next
pointerB = pointerB.next
if not pointerB.next:
bbot = pointerB.val
if pointerA.next:
pointerA = pointerA.next
pointerB = headA
while pointerA.next:
pointerA = pointerA.next
pointerB = pointerB.next
abot = pointerA.val
pointerA = headB
pointerB = pointerB.next
if abot != bbot:
return None
while True:
if pointerB == pointerA:
return pointerA
else:
pointerB = pointerB.next
pointerA = pointerA.next
我这个代码显得很笨重,太蠢了,我看了看评论区里相同的思路的做法的代码,又惊了,先贴上来看看:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# @param two ListNodes
# @return the intersected ListNode
def getIntersectionNode(self, headA, headB):
if headA is None or headB is None:
return None
pa = headA # 2 pointers
pb = headB
while pa is not pb:
# if either pointer hits the end, switch head and continue the second traversal,
# if not hit the end, just move on to next
pa = headB if pa is None else pa.next
pb = headA if pb is None else pb.next
return pa # only 2 ways to get out of the loop, they meet or the both hit the end=None
# the idea is if you switch head, the possible difference between length would be countered.
# On the second traversal, they either hit or miss.
# if they meet, pa or pb would be the node we are looking for,
# if they didn't meet, they will hit the end at the same iteration, pa == pb == None, return either one of them is the same,None
代码写的及其简洁,但我想到的问题里面都有很巧妙地解决,精华就在于这两行代码:
pa = headB if pa is None else pa.next
pb = headA if pb is None else pb.next
这两行很完美的解决了先到之后换头和继续走的问题,并且如果两个没有交点的话,他们换头之后会同时走到终点然后基于while的条件而退出