offer47的要求很简单:输入两个链表,找出它们的第一个公共结点。
又先搬一张图,最近画图很懒啊……
二次遍历
方法有很多,除了暴力方法外,我最先想到的是二次遍历:先获得两个链表的长度,然后在较长的链表上先走若干步(两链表长度之差),接着同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共节点。时间复杂度O(m + n)。
# offer47-solution 1
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
length1 = self.GetLength(pHead1)
length2 = self.GetLength(pHead2)
if length1 > length2:
headLong = pHead1
headShort = pHead2
else:
headLong = pHead2
headShort = pHead1
diff = abs(length1 - length2)
for i in range(diff):
headLong = headLong.next # 长链表的指针先走
while headLong != None and headShort != None and headLong != headShort: # 没到尾,也没相同,接着走
headLong = headLong.next
headShort = headShort.next
return headLong
def GetLength(self, pHead): # 先遍历一次求长度
length = 0
while pHead:
pHead = pHead.next
length += 1
return length
玄学
以下是一段通过二次遍历改造的玄学代码,请读者回去自行研究哈哈哈哈哈。
# offer47-solution 2
def FindFirstCommonNode(self, pHead1, pHead2):
p1, p2 = pHead1, pHead2
while p1 != p2:
p1 = p1.next if p1 != None else pHead2
p2 = p2.next if p2 != None else pHead1
return p1
辅助栈
辅助栈的方法,见参考链接:
【剑指offer】37. 两个链表的第一个公共节点(python)
同样是遍历两个链表,将节点保存到栈中。然后利用栈先进后出的特点找到公共节点。
# offer47-solution 3
class Solution:
def FindFirstCommonNode(self, pHead1, pHead2):
# write code here
while not pHead1 or not pHead2:
return None
# 遍历两个链表,将节点保存到栈中
# 然后利用栈先进后出的特点找到公共节点
stack1 = []
stack2 = []
while pHead1:
stack1.append(pHead1)
pHead1 = pHead1.next
while pHead2:
stack2.append(pHead2)
pHead2 = pHead2.next
commonNode = None
while stack2 and stack1:
node1 = stack1.pop()
node2 = stack2.pop()
if node1 != node2:
break
else:
commonNode = node1
return commonNode
个人还是觉得常规的二次遍历好想好写,但是方法3有助于加强栈的运用的熟练性。