首页 如何检测两个单链表(无环)是否交叉?
文章
取消

如何检测两个单链表(无环)是否交叉?

题目

单链表相交,是指两个单链表存在完全重合的部分。对于两个单链表(无环),如何检测是否交叉?

解法

用 set/map 存储并检测

和上篇文章的常规思路相似,如果交叉,则存在相同的节点。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
func checkCross(head1 *LNode, head2 *LNode) bool {
	if head1 == nil || head2 == nil {
		return false
	}

	tmp := make(map[*LNode]interface{})

	// 将单链表1中的节点全部存起来
	cur1 := head1.Next
	for cur1 != nil {
		tmp[cur1] = nil
		cur1 = cur1.Next
	}
	// 遍历单链表2
	cur2 := head2.Next
	for cur2 != nil {
		if _, ok := tmp[cur2]; ok {
			// 找到相同节点
			return true
		}
		cur2 = cur2.Next
	}
	return false
}

func main() {
	node1 := &LNode{Data: 1}
	node2 := &LNode{Data: 2}
	node3 := &LNode{Data: 3}
	node4 := &LNode{Data: 4}
	node5 := &LNode{Data: 5}

	// l1: 1->2->3->4->5
	l1 := NewLList()
	l1.Next = node1
	node1.Next = node2
	node2.Next = node3
	node3.Next = node4
	node4.Next = node5

	// l2: 6->7->4->5
	l2 := NewLList()
	node6 := &LNode{Data: 6}
	node7 := &LNode{Data: 7}
	l2.Next = node6
	node6.Next = node7
	node7.Next = node4

	// l3: 8->9->10->11
	l3 := NewLList()
	node8 := &LNode{Data: 8}
	node9 := &LNode{Data: 9}
	node10 := &LNode{Data: 10}
	node11 := &LNode{Data: 11}
	l3.Next = node8
	node8.Next = node9
	node9.Next = node10
	node10.Next = node11

	isCross := checkCross(l1, l2)
    // l1与l2相交? true
	fmt.Println("l1与l2相交?", isCross)

	isCross = checkCross(l1, l3)
    // l1与l2相交? false
	fmt.Println("l1与l3相交?", isCross)
}

构成带环单链表

受上篇文章的启发,如果两个单链表交叉,则如果把单链表1的尾部链接到单链表2的头部,则可以构成一个带环的单链表,这时再检测是否带环就可以了。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
func checkRing(head *LNode) bool {
	if head == nil || head.Next == nil {
		return false
	}

	slow := head.Next
	fast := head.Next

	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next
		if slow == fast {
			return true
		}
	}
	return false
}

func checkCross(head1, head2 *LNode) bool {
	if head1 == nil || head2 == nil {
		return false
	}

	cur := head1.Next
	for cur.Next != nil {
		cur = cur.Next
	}
	// cur 此时是 head1的尾部,将其链接到 head2 上
	cur.Next = head2.Next

	return checkRing(head1)
}

func main() {
	node1 := &LNode{Data: 1}
	node2 := &LNode{Data: 2}
	node3 := &LNode{Data: 3}
	node4 := &LNode{Data: 4}
	node5 := &LNode{Data: 5}

	// l1: 1->2->3->4->5
	l1 := NewLList()
	l1.Next = node1
	node1.Next = node2
	node2.Next = node3
	node3.Next = node4
	node4.Next = node5

	// l2: 6->7->4->5
	l2 := NewLList()
	node6 := &LNode{Data: 6}
	node7 := &LNode{Data: 7}
	l2.Next = node6
	node6.Next = node7
	node7.Next = node4

	// l3: 8->9->10->11
	l3 := NewLList()
	node8 := &LNode{Data: 8}
	node9 := &LNode{Data: 9}
	node10 := &LNode{Data: 10}
	node11 := &LNode{Data: 11}
	l3.Next = node8
	node8.Next = node9
	node9.Next = node10
	node10.Next = node11

	// l4: 12->13->14
	l4 := NewLList()
	node12 := &LNode{Data: 12}
	node13 := &LNode{Data: 13}
	node14 := &LNode{Data: 14}

	l4.Next = node12
	node12.Next = node13
	node13.Next = node14

	isCross := checkCross(l1, l2)
	// l1与l2相交? true
	fmt.Println("l1与l2相交?", isCross)

	isCross = checkCross(l3, l4)
	// l3与l4相交? false
	fmt.Println("l3与l4相交?", isCross)
}
本文由作者按照 CC BY 4.0 进行授权