Skip to content

Commit 5a8ae3f

Browse files
authored
feat: add solutions to lcci/lcof2 problems (#2530)
* lcci No.02.08.Linked List Cycle * lcof2 No.022.链表中环的入口节点 * lcof2 No.023.两个链表的第一个重合节点
1 parent 1f10d17 commit 5a8ae3f

File tree

24 files changed

+618
-428
lines changed

24 files changed

+618
-428
lines changed

.github/pull_request_template.md

-15
Original file line numberDiff line numberDiff line change
@@ -1,16 +1 @@
11

2-
3-
<!--
4-
Below are template for copilot to generate CR message.
5-
Please DO NOT modify it.
6-
7-
8-
### Description
9-
10-
copilot:summary
11-
12-
### Explanation of Changes
13-
14-
copilot:walkthrough
15-
16-
-->

lcci/02.08.Linked List Cycle/README.md

+107-70
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,25 @@
1010

1111
## 解法
1212

13-
### 方法一
13+
### 方法一:快慢指针
14+
15+
我们先利用快慢指针判断链表是否有环,如果有环的话,快慢指针一定会相遇,且相遇的节点一定在环中。
16+
17+
如果没有环,快指针会先到达链表尾部,直接返回 `null` 即可。
18+
19+
如果有环,我们再定义一个答案指针 $ans$ 指向链表头部,然后让 $ans$ 和慢指针一起向前走,每次走一步,直到 $ans$ 和慢指针相遇,相遇的节点即为环的入口节点。
20+
21+
为什么这样能找到环的入口节点呢?
22+
23+
我们不妨假设链表头节点到环入口的距离为 $x$,环入口到相遇节点的距离为 $y$,相遇节点到环入口的距离为 $z$,那么慢指针走过的距离为 $x + y$,快指针走过的距离为 $x + y + k \times (y + z)$,其中 $k$ 是快指针在环中绕了 $k$ 圈。
24+
25+
<p><img src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/lcci/02.08.Linked%20List%20Cycle/images/linked-list-cycle-ii.png" /></p>
26+
27+
由于快指针速度是慢指针的 $2$ 倍,因此有 $2 \times (x + y) = x + y + k \times (y + z)$,可以推出 $x + y = k \times (y + z)$,即 $x = (k - 1) \times (y + z) + z$。
28+
29+
也即是说,如果我们定义一个答案指针 $ans$ 指向链表头部,然后 $ans$ 和慢指针一起向前走,那么它们一定会在环入口相遇。
30+
31+
时间复杂度 $O(n)$,其中 $n$ 是链表中节点的数目。空间复杂度 $O(1)$。
1432

1533
<!-- tabs:start -->
1634

@@ -23,18 +41,17 @@
2341

2442

2543
class Solution:
26-
def detectCycle(self, head: ListNode) -> ListNode:
27-
slow = fast = head
28-
has_cycle = False
29-
while not has_cycle and fast and fast.next:
30-
slow, fast = slow.next, fast.next.next
31-
has_cycle = slow == fast
32-
if not has_cycle:
33-
return None
34-
p = head
35-
while p != slow:
36-
p, slow = p.next, slow.next
37-
return p
44+
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
45+
fast = slow = head
46+
while fast and fast.next:
47+
slow = slow.next
48+
fast = fast.next.next
49+
if slow == fast:
50+
ans = head
51+
while ans != slow:
52+
ans = ans.next
53+
slow = slow.next
54+
return ans
3855
```
3956

4057
```java
@@ -51,22 +68,20 @@ class Solution:
5168
*/
5269
public class Solution {
5370
public ListNode detectCycle(ListNode head) {
54-
ListNode slow = head, fast = head;
55-
boolean hasCycle = false;
56-
while (!hasCycle && fast != null && fast.next != null) {
71+
ListNode fast = head, slow = head;
72+
while (fast != null && fast.next != null) {
5773
slow = slow.next;
5874
fast = fast.next.next;
59-
hasCycle = slow == fast;
75+
if (slow == fast) {
76+
ListNode ans = head;
77+
while (ans != slow) {
78+
ans = ans.next;
79+
slow = slow.next;
80+
}
81+
return ans;
82+
}
6083
}
61-
if (!hasCycle) {
62-
return null;
63-
}
64-
ListNode p = head;
65-
while (p != slow) {
66-
p = p.next;
67-
slow = slow.next;
68-
}
69-
return p;
84+
return null;
7085
}
7186
}
7287
```
@@ -83,23 +98,21 @@ public class Solution {
8398
class Solution {
8499
public:
85100
ListNode* detectCycle(ListNode* head) {
86-
ListNode* slow = head;
87101
ListNode* fast = head;
88-
bool hasCycle = false;
89-
while (!hasCycle && fast && fast->next) {
102+
ListNode* slow = head;
103+
while (fast && fast->next) {
90104
slow = slow->next;
91105
fast = fast->next->next;
92-
hasCycle = slow == fast;
93-
}
94-
if (!hasCycle) {
95-
return nullptr;
106+
if (slow == fast) {
107+
ListNode* ans = head;
108+
while (ans != slow) {
109+
ans = ans->next;
110+
slow = slow->next;
111+
}
112+
return ans;
113+
}
96114
}
97-
ListNode* p = head;
98-
while (p != slow) {
99-
p = p->next;
100-
slow = slow->next;
101-
}
102-
return p;
115+
return nullptr;
103116
}
104117
};
105118
```
@@ -113,20 +126,51 @@ public:
113126
* }
114127
*/
115128
func detectCycle(head *ListNode) *ListNode {
116-
slow, fast := head, head
117-
hasCycle := false
118-
for !hasCycle && fast != nil && fast.Next != nil {
119-
slow, fast = slow.Next, fast.Next.Next
120-
hasCycle = slow == fast
121-
}
122-
if !hasCycle {
123-
return nil
129+
fast, slow := head, head
130+
for fast != nil && fast.Next != nil {
131+
slow = slow.Next
132+
fast = fast.Next.Next
133+
if slow == fast {
134+
ans := head
135+
for ans != slow {
136+
ans = ans.Next
137+
slow = slow.Next
138+
}
139+
return ans
140+
}
124141
}
125-
p := head
126-
for p != slow {
127-
p, slow = p.Next, slow.Next
128-
}
129-
return p
142+
return nil
143+
}
144+
```
145+
146+
```ts
147+
/**
148+
* Definition for singly-linked list.
149+
* class ListNode {
150+
* val: number
151+
* next: ListNode | null
152+
* constructor(val?: number, next?: ListNode | null) {
153+
* this.val = (val===undefined ? 0 : val)
154+
* this.next = (next===undefined ? null : next)
155+
* }
156+
* }
157+
*/
158+
159+
function detectCycle(head: ListNode | null): ListNode | null {
160+
let [slow, fast] = [head, head];
161+
while (fast && fast.next) {
162+
slow = slow.next;
163+
fast = fast.next.next;
164+
if (slow === fast) {
165+
let ans = head;
166+
while (ans !== slow) {
167+
ans = ans.next;
168+
slow = slow.next;
169+
}
170+
return ans;
171+
}
172+
}
173+
return null;
130174
}
131175
```
132176

@@ -144,26 +188,19 @@ func detectCycle(head *ListNode) *ListNode {
144188
* @return {ListNode}
145189
*/
146190
var detectCycle = function (head) {
147-
let slow = head;
148-
let fast = head;
149-
let hasCycle = false;
150-
while (!hasCycle && fast && fast.next) {
191+
let [slow, fast] = [head, head];
192+
while (fast && fast.next) {
151193
slow = slow.next;
152194
fast = fast.next.next;
153-
hasCycle = slow == fast;
154-
}
155-
if (!hasCycle) {
156-
return null;
157-
}
158-
let p = head;
159-
while (p != slow) {
160-
p = p.next;
161-
slow = slow.next;
195+
if (slow === fast) {
196+
let ans = head;
197+
while (ans !== slow) {
198+
ans = ans.next;
199+
slow = slow.next;
200+
}
201+
return ans;
202+
}
162203
}
163-
return p;
204+
return null;
164205
};
165206
```
166-
167-
<!-- tabs:end -->
168-
169-
<!-- end -->

0 commit comments

Comments
 (0)