## 题目地址 https://leetcode.com/problems/reverse-linked-list-ii/description/ ## 题目描述 Reverse a linked list from position m to n. Do it in one-pass. Note: 1 ≤ m ≤ n ≤ length of list. Example: Input: 1->2->3->4->5->NULL, m = 2, n = 4 Output: 1->4->3->2->5->NULL ## 思路 考虑取出需要反转的这一小段链表,反转完后再插入到原先的链表中。 以本题为例: 变换的是2,3,4这三个点,那么我们可以先取出2,用front指针指向2,然后当取出3的时候,我们把3加到2的前面,把front指针前移到3,依次类推,到4后停止,这样我们得到一个新链表4->3->2, front指针指向4。 对于原链表来说,有两个点的位置很重要,需要用指针记录下来,分别是1和5,把新链表插入的时候需要这两个点的位置。 用pre指针记录1的位置 当4结点被取走后,5的位置需要记下来 这样我们就可以把倒置后的那一小段链表加入到原链表中 ![92.reverse-linked-list-ii](../assets/92.reverse-linked-list-ii.gif) (图片来自: https://github.com/MisterBooo/LeetCodeAnimation) ## 关键点解析 - 链表的基本操作(交换) - 虚拟节点dummy 简化操作 - 考虑特殊情况 m 是 1 或者 n是链表长度的情况 - 用四个变量记录特殊节点, 然后操作这四个节点使之按照一定方式连接即可。 ```js let midStartNode = null; let preMidStartNode = null; let midEndNode = null; let postMidEndNode = null; ``` - 注意更新current和pre的位置, 否则有可能出现溢出 ## 代码 ```js /* * @lc app=leetcode id=92 lang=javascript * * [92] Reverse Linked List II * * https://leetcode.com/problems/reverse-linked-list-ii/description/ * * algorithms * Medium (34.13%) * Total Accepted: 182.3K * Total Submissions: 532.8K * Testcase Example: '[1,2,3,4,5]\n2\n4' * * Reverse a linked list from position m to n. Do it in one-pass. * * Note: 1 ≤ m ≤ n ≤ length of list. * * Example: * * * Input: 1->2->3->4->5->NULL, m = 2, n = 4 * Output: 1->4->3->2->5->NULL * * */ /** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} head * @param {number} m * @param {number} n * @return {ListNode} */ var reverseBetween = function(head, m, n) { // 虚拟节点,简化操作 const dummyHead = { next: head } let current = dummyHead.next; // 当前遍历的节点 let pre = current; // 因为要反转,因此我们需要记住前一个节点 let index = 0; // 链表索引,用来判断是否是特殊位置(头尾位置) // 上面提到的四个特殊节点 let midStartNode = null; let preMidStartNode = null; let midEndNode = null; let postMidEndNode = null; while(current) { const next = current.next; index++; // 对 (m - n) 范围内的节点进行反转 if (index > m && index <= n) { current.next = pre; } // 下面四个if都是边界, 用于更新四个特殊节点的值 if (index === m - 1) { preMidStartNode = current; } if (index === m) { midStartNode = current; } if (index === n + 1) { postMidEndNode = current; } if (index === n) { midEndNode = current;; } pre = current; current = next; } // 两个链表合并起来 (preMidStartNode || dummyHead).next = midEndNode; // 特殊情况需要考虑 midStartNode.next = postMidEndNode; return dummyHead.next; }; ```