(经典)求两个单链表相交结点

题目描述

在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null即可。 要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到O(N+M),额外空间复杂度请达到O(1)。

考察点

  • 判断链表是否有环
  • 如果链表有环,则找到入环结点
  • 两个链表各种情况的分析

情况分析

这道题总共有6种情况要分析。分别是

  • 两个链表无环
  • 两个链表有环
  • 一个链表有环,一个链表无环

img

1、如果两个链表都无环,那就直接判断是否相交即可。

2、如果两个链表都有环,求出入口节点。

求出入口节点,如果入口节点是同一个的话,把相同的入口结点当作是尾结点,这个问题就退化成两个链表都无环,直接判断是否相交即可。

如果入口节点不是同一个的话,从第一个入口节点开始next下去,如果遇到第二个入口节点返回即可;如果回到了本身的入口节点则表示没有相交,直接返回null

3、如果一个链表有环一个链表无环,那么这两个链表必不可能相交

所有的情况就都已经分析完了,接下来就是上代码了

代码

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package zuoshen;

/**
* @author god-jiang
* @date 2020/2/12 11:00
*/
public class FindFirstIntersectNode {
//Java版.左老师给出的代码,很赞
public static class Node {
public int value;
public Node next;

public Node(int data) {
this.value = data;
}
}

public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
//求head1和head2的入环结点
Node loop1 = getLoopNode(head1);
Node loop2 = getLoopNode(head2);
//head1和head2都没有环
if (loop1 == null && loop2 == null) {
return noLoop(head1, head2);
}
//head1和head2都有环
if (loop1 != null && loop2 != null) {
return bothLoop(head1, loop1, head2, loop2);
}
//当一个有环一个无环则不存在相交结点
return null;
}

public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node n1 = head.next; // n1 -> slow
Node n2 = head.next.next; // n2 -> fast
while (n1 != n2) {
if (n2.next == null || n2.next.next == null) {
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
n2 = head; // n2 -> walk again from head
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}

public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}

public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
n--;
cur2 = cur2.next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {
cur1 = loop1.next;
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;
}
cur1 = cur1.next;
}
return null;
}
}

public static void main(String[] args) {
// 1->2->3->4->5->6->7->null
Node head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);

// 0->9->8->6->7->null
Node head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);//output:6

// 1->2->3->4->5->6->7->4...
head1 = new Node(1);
head1.next = new Node(2);
head1.next.next = new Node(3);
head1.next.next.next = new Node(4);
head1.next.next.next.next = new Node(5);
head1.next.next.next.next.next = new Node(6);
head1.next.next.next.next.next.next = new Node(7);
head1.next.next.next.next.next.next.next = head1.next.next.next; // 7->4

// 0->9->8->2...
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next; // 8->2
System.out.println(getIntersectNode(head1, head2).value);//output:2

// 0->9->8->6->4->5->6..
head2 = new Node(0);
head2.next = new Node(9);
head2.next.next = new Node(8);
head2.next.next.next = head1.next.next.next.next.next; // 8->6
System.out.println(getIntersectNode(head1, head2).value);//output:4
System.out.println(getIntersectNode(head2, head1).value);//note the order //output:6

}

}

总结

这道题其实是挺难的,但是听了左神老师讲完之后发现也就那样。由此可见,一道难的题目都是由一些简单的题目组合起来的。这道题就是两个无环链表判断相交并且返回相交节点,有环链表求它的入环节点,这两道题目的组合就是今天这道题的由来,所以情况更加的复杂。

-------------本文结束感谢您的阅读-------------

本文标题:(经典)求两个单链表相交结点

文章作者:god-jiang

发布时间:2020年02月12日 - 11:40:06

最后更新:2020年02月12日 - 12:10:22

原始链接:https://god-jiang.github.io/2020/02/12/(经典)求两个单链表相交结点/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

创作不易,您的支持就是我坚持的动力,谢谢大家!
0%