@@ -13,37 +13,101 @@ Output: 1->4->3->2->5->NULL
13
13
14
14
## 思路
15
15
16
- 考虑取出需要反转的这一小段链表,反转完后再插入到原先的链表中 。
16
+ 这道题和 [ 206.reverse-linked-list ] ( https://github.com/azl397985856/leetcode/blob/master/problems/206.reverse-linked-list.md ) 有点类似,并且这道题是206的升级版。 让我们反转某一个区间,而不是整个链表,我们可以将206看作本题的特殊情况(special case) 。
17
17
18
- 以本题为例:
19
-
20
- 变换的是2,3,4这三个点,那么我们可以先取出2,用front指针指向2,然后当取出3的时候,我们把3加到2的前面,把front指针前移到3,依次类推,到4后停止,这样我们得到一个新链表4->3->2, front指针指向4。
18
+ 核心在于** 取出需要反转的这一小段链表,反转完后再插入到原先的链表中。**
21
19
22
- 对于原链表来说,有两个点的位置很重要,需要用指针记录下来,分别是1和5,把新链表插入的时候需要这两个点的位置。
20
+ 以本题为例:
23
21
24
- 用pre指针记录1的位置
22
+ 反转的是2,3,4这三个点,那么我们可以先取出2,用cur指针指向2,然后当取出3的时候,我们将3指向2的,把cur指针前移到3,依次类推,到4后停止,这样我们得到一个新链表4->3->2, cur指针指向4。
25
23
26
- 当4结点被取走后 ,5的位置需要记下来
24
+ 对于原链表来说,有两个点的位置很重要,需要用指针记录下来,分别是1和5,把新链表插入的时候需要这两个点的位置。用pre指针记录1的位置当4结点被取走后 ,5的位置需要记下来
27
25
28
- 这样我们就可以把倒置后的那一小段链表加入到原链表中
26
+ 这样我们就可以把反转后的那一小段链表加入到原链表中
29
27
30
28
![ 92.reverse-linked-list-ii] ( ../assets/92.reverse-linked-list-ii.gif )
31
29
32
30
(图片来自: https://github.com/MisterBooo/LeetCodeAnimation )
33
- ## 关键点解析
34
31
35
- - 链表的基本操作(交换)
36
- - 虚拟节点dummy 简化操作
37
- - 考虑特殊情况 m 是 1 或者 n是链表长度的情况
38
- - 用四个变量记录特殊节点, 然后操作这四个节点使之按照一定方式连接即可。
39
32
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
45
50
```
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
+ ```
46
105
106
+ ## 关键点解析
107
+
108
+ - 链表的基本操作
109
+ - 考虑特殊情况 m 是 1 或者 n是链表长度的情况,我们可以采用虚拟节点dummy 简化操作
110
+ - 用四个变量记录特殊节点, 然后操作这四个节点使之按照一定方式连接即可。
47
111
- 注意更新current和pre的位置, 否则有可能出现溢出
48
112
49
113
@@ -60,24 +124,6 @@ JavaScript Code:
60
124
* [92] Reverse Linked List II
61
125
*
62
126
* 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
- *
81
127
*/
82
128
/**
83
129
* Definition for singly-linked list.
@@ -98,49 +144,46 @@ var reverseBetween = function(head, m, n) {
98
144
next: head
99
145
}
100
146
101
- let current = dummyHead .next ; // 当前遍历的节点
102
- let pre = current ; // 因为要反转,因此我们需要记住前一个节点
147
+ let cur = dummyHead .next ; // 当前遍历的节点
148
+ let pre = cur ; // 因为要反转,因此我们需要记住前一个节点
103
149
let index = 0 ; // 链表索引,用来判断是否是特殊位置(头尾位置)
104
150
105
151
// 上面提到的四个特殊节点
106
- let midStartNode = null ;
107
- let preMidStartNode = null ;
108
- let midEndNode = null ;
109
- let postMidEndNode = null ;
152
+ let p1 = p2 = p3 = p4 = null
110
153
111
- while (current ) {
112
- const next = current .next ;
154
+ while (cur ) {
155
+ const next = cur .next ;
113
156
index++ ;
114
157
115
158
// 对 (m - n) 范围内的节点进行反转
116
159
if (index > m && index <= n) {
117
- current .next = pre;
160
+ cur .next = pre;
118
161
}
119
162
120
163
// 下面四个if都是边界, 用于更新四个特殊节点的值
121
164
if (index === m - 1 ) {
122
- preMidStartNode = current ;
165
+ p1 = cur ;
123
166
}
124
167
if (index === m) {
125
- midStartNode = current ;
168
+ p2 = cur ;
126
169
}
127
170
128
- if (index === n + 1 ) {
129
- postMidEndNode = current ;
171
+ if (index === n) {
172
+ p3 = cur ;
130
173
}
131
174
132
- if (index === n) {
133
- midEndNode = current ;;
175
+ if (index === n + 1 ) {
176
+ p4 = cur ;;
134
177
}
135
178
136
- pre = current ;
179
+ pre = cur ;
137
180
138
- current = next;
181
+ cur = next;
139
182
}
140
183
141
184
// 两个链表合并起来
142
- (preMidStartNode || dummyHead).next = midEndNode ; // 特殊情况需要考虑
143
- midStartNode .next = postMidEndNode ;
185
+ (p1 || dummyHead).next = p3 ; // 特殊情况需要考虑
186
+ p2 .next = p4 ;
144
187
145
188
return dummyHead .next ;
146
189
};
0 commit comments