时间复杂度:O(n),空间复杂度:O(1)
解题思路
要说时间复杂度为O(n)的能想到的最简单的方法就是让两个链表的尾部对齐截去长链表的多余部分使二者长度相同,然后同步遍历两个链表节点比较是否相等,直到遍历到链表尾部。
所以我们需要先遍历两个链表知道二者的长度,然后根据长度的差值截去较长链表的多余部分,最后同步遍历两链表并比较即可。
上述方法的精确时间复杂度为O(m+n+min(m,n)),在面试时可能不满足面试官要求的O(m+n)时间复杂度,所以这时我们就要用如下所述的官方题解的方法了。
让两个指针分别从两链表表头开始遍历,如果短链表指针遍历完且此时长链表指针未遍历完,则让短链表指针从长链表的表头开始遍历,同理长链表指针遍历完也来遍历短链表,直至两指针的节点相同,此时的节点就是相交节点。
对于证明,可以设两链表的相交节点个数为c,长链表除相交节点外的节点数为a,短链表除相交节点外的节点数为b。这样当短链表指针遍历完时走了b+c,接下来短链表指针去遍历长链表后走了a步到达再次到达相交头节点,短链表指针总共走了b+c+a步,而此时长链表指针也走了a+c+b步,所以二者相遇时的结点就是相交节点。
AC代码
最优解法
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
p1,p2:=headA,headB
for p1!=p2{
if p1==nil{
p1=headB
}else{
p1=p1.Next
}
if p2==nil{
p2=headA
}else{
p2=p2.Next
}
}
return p1
}
容易想到的长度对齐法
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
aLen,bLen:=0,0
p1,p2:=headA,headB
for p1!=nil{
aLen++
p1=p1.Next
}
for p2!=nil{
bLen++
p2=p2.Next
}
if aLen>bLen{
for aLen>bLen{
headA=headA.Next
aLen--
}
}else{
for bLen>aLen{
headB=headB.Next
bLen--
}
}
for headA!=nil{
if headA==headB{
return headA
}
headA=headA.Next
headB=headB.Next
}
return nil
}
感悟
一般只能想到让两链表剩余长度相同的解法,但最好的方法是让两链表指针交互遍历。
二刷感悟
二刷再看题目时,立刻想到了遍历两链表然后尾部对齐的方法,再想一想好像最优解法是相互遍历的方法,具体有点记不清了。看了题解后加深了一遍印象,并且很顺利地写出了最优解法的代码,比容易想到的方法简洁许多。