0%

LeetCode-160

题目

160. 相交链表

代码

求两个链表的相交部分(共同部分),很容易想到的是用集合(指针也能作为Map的key):

1
2
3
4
5
6
7
8
9
10
11
12
13
func getIntersectionNode(headA, headB *ListNode) *ListNode {
set := make(map[*ListNode]bool)
for p := headA; p != nil; p = p.Next {
set[p] = true
}

for p := headB; p != nil; p = p.Next {
if _, ok := set[p]; ok {
return p
}
}
return nil
}

这种方法有线性级别的时间和空间复杂度。

我想到一种精彩的譬喻,可以把两个链表看做是两个赛道,这两个赛道长度不同但终点却在同一处。

位于两个赛道上的两个速度相同的选手同时出发,因为赛道长度不同,到达终点的时刻必然不同,但两条赛道的长度和却是一样的(A+B=B+A)。

如果让到达终点的选手立即再去以相同的速度跑另一个赛道,两个选手必能同时到达终点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func getIntersectionNode(headA, headB *ListNode) *ListNode {
pa, pb := headA, headB
for pa != pb {
if pa != nil {
pa = pa.Next
} else {
pa = headB
}
if pb != nil {
pb = pb.Next
} else {
pb = headA
}
}
return pa
}

上面的方法拥有线性级别的时间复杂度和常数级别的空间复杂度。

此前还想到这种解法,复杂度都差不多,因为“本质”都一样,但我很难描述这种“本质”。。T—T

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func getIntersectionNode(headA, headB *ListNode) *ListNode {
lenA := length(headA)
lenB := length(headB)
for {
if lenA == 0 || lenB == 0 {
return nil
}
if headA == headB {
return headA
} else {
if lenA > lenB {
headA = headA.Next
lenA--
} else if lenA == lenB {
headA = headA.Next
lenA--
headB = headB.Next
lenB--
} else {
headB = headB.Next
lenB--
}
}
}
}

func length(head *ListNode) (ans int) {
for p := head; p != nil; p = p.Next {
ans++
}
return
}