@@ -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