/** * Definition for singly-linked list. * function ListNode(val, next) { * this.val = (val===undefined ? 0 : val) * this.next = (next===undefined ? null : next) * } */ /** * https://leetcode.cn/problems/reverse-linked-list-ii/?envType=study-plan-v2&envId=top-interview-150 * @param {ListNode} head * @param {number} left * @param {number} right * @return {ListNode} */ const reverseBetween = function (head, left, right) { }; /* 思路: 首先找到left指向的节点和right指向的节点,之后把left的前一个节点和right的后一个节点保存起来 ,之后反转left到right的所有节点,再把原先得前后两部分拼接上即可。 */ function f1(head, left, right) { if (left === right) return head; // 无需反转 let cur = head; let i = 1; let pre = null; let leftNode = null; let rightNode = null; let next = null; while (cur) { if (i === left - 1) { // 寻找left的前一个节点 pre = cur; } else if (i === left) { // 寻找left节点 leftNode = cur; } else if (i === right) { // 寻找right 节点 rightNode = cur; next = cur.next; rightNode.next = null; // 将链表截断 break; // 退出循环 } cur = cur.next; i++; } // 从left到right开始反转 const rHead = reverseLink(leftNode); // rHead和RightNode指向了同一个节点 if (pre) { pre.next = rHead; } else { head = rightNode; } leftNode.next = next; return head; } /* 反转一个链表,使用递归 */ function reverseLink(head) { // 基本情况:如果链表为空或只有一个节点,直接返回 if (!head || !head.next) return head; // 递归反转后续链表 const rHead = reverseLink(head.next); // 当前节点的下一个节点的 next 指向当前节点,反转链表 head.next.next = head; // 断开当前节点与下一个节点的连接,防止形成环 head.next = null; return rHead; } /* 反转一个链表使用迭代 */ const reverseLinkedList = (head) => { let pre = null; let cur = head; while (cur) { const next = cur.next; cur.next = pre; pre = cur; cur = next; } }; function ListNode(val, next) { this.val = (val === undefined ? 0 : val); this.next = (next === undefined ? null : next); } /* 优化:思路和上面是一样的,利用哑节点来优化,减少边界判断情况 */ function f2(head, left, right) { // left在等于1时和大于1时处理方式不同,利用哑节点来减少判断情况 const dummyHead = new ListNode(-1); dummyHead.next = head; // 1.寻找left节点的前一个节点pre // 这里直接使用for循环,从dummyHead的位置走left-1步即可 let pre = dummyHead; for (let i = 0; i < left - 1; i++) { pre = pre.next; } // 2.从pre的位置往后走 right - Left + 1步,即可找到right指向的节点 let rightNode = pre; for (let i = 0; i < right - left + 1; i++) { rightNode = rightNode.next; } // 3.将链表从left到right的位置切断 const leftNode = pre.next; const surr = rightNode.next; pre.next = null; rightNode.next = null; // 4.反转切断的这一部分 reverseLinkedList(leftNode); // 5.接回原来的链表中 pre.next = rightNode; leftNode.next = surr; return dummyHead.next; } /* 直接在链表上面操作,把要反转的区域 */ function f3(head, left, right) { const dummyHead = new ListNode(-1); // 创建一个哑节点,简化边界情况 dummyHead.next = head; // 哑节点的next指向链表头 let pre = dummyHead; // `pre` 用于指向 `left` 前一个节点 // 寻找 `left` 的前一个节点 for (let i = 0; i < left - 1; i++) { pre = pre.next; } const cur = pre.next; // `cur` 指向要反转部分的第一个节点 // 从 `left` 到 `right` 反转链表部分 for (let i = 0; i < right - left; i++) { const next = cur.next; // `next` 指向当前节点的下一个节点 cur.next = next.next; // 跳过 `next` 节点 next.next = pre.next; // 将 `next` 插入到 `cur` 前面 pre.next = next; // 更新 `pre.next` 为 `next` } return dummyHead.next; // 返回反转后的链表 }