Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 98d0e91

Browse files
author
lucifer
committed
2 parents 55c81ba + bfef968 commit 98d0e91

File tree

2 files changed

+99
-56
lines changed

2 files changed

+99
-56
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
179179
- [0086.partition-list](./problems/86.partition-list.md)
180180
- [0090.subsets-ii](./problems/90.subsets-ii.md)
181181
- [0091.decode-ways](./problems/91.decode-ways.md)
182-
- [0092.reverse-linked-list-ii](./problems/92.reverse-linked-list-ii.md)
182+
- [0092.reverse-linked-list-ii](./problems/92.reverse-linked-list-ii.md) 🖊
183183
- [0094.binary-tree-inorder-traversal](./problems/94.binary-tree-inorder-traversal.md)
184184
- [0095.unique-binary-search-trees-ii](./problems/95.unique-binary-search-trees-ii.md) 🆕
185185
- [0096.unique-binary-search-trees](./problems/96.unique-binary-search-trees.md) 🆕

problems/92.reverse-linked-list-ii.md

Lines changed: 98 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,101 @@ Output: 1->4->3->2->5->NULL
1313

1414
## 思路
1515

16-
考虑取出需要反转的这一小段链表,反转完后再插入到原先的链表中
16+
这道题和[206.reverse-linked-list](https://github.com/azl397985856/leetcode/blob/master/problems/206.reverse-linked-list.md) 有点类似,并且这道题是206的升级版。 让我们反转某一个区间,而不是整个链表,我们可以将206看作本题的特殊情况(special case)
1717

18-
以本题为例:
19-
20-
变换的是2,3,4这三个点,那么我们可以先取出2,用front指针指向2,然后当取出3的时候,我们把3加到2的前面,把front指针前移到3,依次类推,到4后停止,这样我们得到一个新链表4->3->2, front指针指向4。
18+
核心在于**取出需要反转的这一小段链表,反转完后再插入到原先的链表中。**
2119

22-
对于原链表来说,有两个点的位置很重要,需要用指针记录下来,分别是1和5,把新链表插入的时候需要这两个点的位置。
20+
以本题为例:
2321

24-
用pre指针记录1的位置
22+
反转的是2,3,4这三个点,那么我们可以先取出2,用cur指针指向2,然后当取出3的时候,我们将3指向2的,把cur指针前移到3,依次类推,到4后停止,这样我们得到一个新链表4->3->2, cur指针指向4。
2523

26-
当4结点被取走后,5的位置需要记下来
24+
对于原链表来说,有两个点的位置很重要,需要用指针记录下来,分别是1和5,把新链表插入的时候需要这两个点的位置。用pre指针记录1的位置当4结点被取走后,5的位置需要记下来
2725

28-
这样我们就可以把倒置后的那一小段链表加入到原链表中
26+
这样我们就可以把反转后的那一小段链表加入到原链表中
2927

3028
![92.reverse-linked-list-ii](../assets/92.reverse-linked-list-ii.gif)
3129

3230
(图片来自: https://github.com/MisterBooo/LeetCodeAnimation)
33-
## 关键点解析
3431

35-
- 链表的基本操作(交换)
36-
- 虚拟节点dummy 简化操作
37-
- 考虑特殊情况 m 是 1 或者 n是链表长度的情况
38-
- 用四个变量记录特殊节点, 然后操作这四个节点使之按照一定方式连接即可。
3932

40-
```js
41-
let midStartNode = null;
42-
let preMidStartNode = null;
43-
let midEndNode = null;
44-
let postMidEndNode = null;
33+
首先我们直接返回head是不行的。 当 m 不等于1的时候是没有问题的,但只要 m 为1,就会有问题。
34+
35+
```python
36+
class Solution:
37+
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
38+
pre = None
39+
cur = head
40+
i = 0
41+
p1 = p2 = p3 = p4 = None
42+
# ...
43+
if p1:
44+
p1.next = p3
45+
else:
46+
dummy.next = p3
47+
if p2:
48+
p2.next = p4
49+
return head
4550
```
51+
52+
如上代码是不可以的,我们考虑使用dummy节点。
53+
```python
54+
class Solution:
55+
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
56+
pre = None
57+
cur = head
58+
i = 0
59+
p1 = p2 = p3 = p4 = None
60+
dummy = ListNode(0)
61+
dummy.next = head
62+
63+
# ...
64+
65+
if p1:
66+
p1.next = p3
67+
else:
68+
dummy.next = p3
69+
if p2:
70+
p2.next = p4
71+
72+
return dummy.next
73+
```
74+
75+
关于链表反转部分, 顺序比较重要,我们需要:
76+
77+
- 先 cur.next = pre
78+
- 再 更新p2和p2.next(其中要设置p2.next = None,否则会互相应用,造成无限循环)
79+
- 最后更新 pre 和 cur
80+
81+
上述的顺序不能错,不然会有问题。原因就在于`p2.next = None`,如果这个放在最后,那么我们的cur会提前断开。
82+
83+
```python
84+
while cur:
85+
i += 1
86+
if i == m - 1:
87+
p1 = cur
88+
next = cur.next
89+
if m < i <= n:
90+
cur.next = pre
91+
92+
if i == m:
93+
p2 = cur
94+
p2.next = None
95+
96+
if i == n:
97+
p3 = cur
98+
99+
if i == n + 1:
100+
p4 = cur
101+
102+
pre = cur
103+
cur = next
104+
```
46105

106+
## 关键点解析
107+
108+
- 链表的基本操作
109+
- 考虑特殊情况 m 是 1 或者 n是链表长度的情况,我们可以采用虚拟节点dummy 简化操作
110+
- 用四个变量记录特殊节点, 然后操作这四个节点使之按照一定方式连接即可。
47111
- 注意更新current和pre的位置, 否则有可能出现溢出
48112

49113

@@ -60,24 +124,6 @@ JavaScript Code:
60124
* [92] Reverse Linked List II
61125
*
62126
* https://leetcode.com/problems/reverse-linked-list-ii/description/
63-
*
64-
* algorithms
65-
* Medium (34.13%)
66-
* Total Accepted: 182.3K
67-
* Total Submissions: 532.8K
68-
* Testcase Example: '[1,2,3,4,5]\n2\n4'
69-
*
70-
* Reverse a linked list from position m to n. Do it in one-pass.
71-
*
72-
* Note: 1 ≤ m ≤ n ≤ length of list.
73-
*
74-
* Example:
75-
*
76-
*
77-
* Input: 1->2->3->4->5->NULL, m = 2, n = 4
78-
* Output: 1->4->3->2->5->NULL
79-
*
80-
*
81127
*/
82128
/**
83129
* Definition for singly-linked list.
@@ -98,49 +144,46 @@ var reverseBetween = function(head, m, n) {
98144
next: head
99145
}
100146

101-
let current = dummyHead.next; // 当前遍历的节点
102-
let pre = current; // 因为要反转,因此我们需要记住前一个节点
147+
let cur = dummyHead.next; // 当前遍历的节点
148+
let pre = cur; // 因为要反转,因此我们需要记住前一个节点
103149
let index = 0; // 链表索引,用来判断是否是特殊位置(头尾位置)
104150

105151
// 上面提到的四个特殊节点
106-
let midStartNode = null;
107-
let preMidStartNode = null;
108-
let midEndNode = null;
109-
let postMidEndNode = null;
152+
let p1 = p2 = p3 = p4 = null
110153

111-
while(current) {
112-
const next = current.next;
154+
while(cur) {
155+
const next = cur.next;
113156
index++;
114157

115158
// 对 (m - n) 范围内的节点进行反转
116159
if (index > m && index <= n) {
117-
current.next = pre;
160+
cur.next = pre;
118161
}
119162

120163
// 下面四个if都是边界, 用于更新四个特殊节点的值
121164
if (index === m - 1) {
122-
preMidStartNode = current;
165+
p1 = cur;
123166
}
124167
if (index === m) {
125-
midStartNode = current;
168+
p2 = cur;
126169
}
127170

128-
if (index === n + 1) {
129-
postMidEndNode = current;
171+
if (index === n) {
172+
p3 = cur;
130173
}
131174

132-
if (index === n) {
133-
midEndNode = current;;
175+
if (index === n + 1) {
176+
p4 = cur;;
134177
}
135178

136-
pre = current;
179+
pre = cur;
137180

138-
current = next;
181+
cur = next;
139182
}
140183

141184
// 两个链表合并起来
142-
(preMidStartNode || dummyHead).next = midEndNode; // 特殊情况需要考虑
143-
midStartNode.next = postMidEndNode;
185+
(p1 || dummyHead).next = p3; // 特殊情况需要考虑
186+
p2.next = p4;
144187

145188
return dummyHead.next;
146189
};

0 commit comments

Comments
 (0)