每日一题--反转链表 II

231 阅读2分钟

这是我参与11月更文挑战的第8天,活动详情查看:[2021最后一次更文挑战]

题目

给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。  

示例 1:


输入:head = [1,2,3,4,5], left = 2, right = 4 输出:[1,4,3,2,5] 示例 2:

输入:head = [5], left = 1, right = 1 输出:[5]

思路 1、我们定义两个指针,分别称之为 g(guard 守卫) 和 p(point)。 我们首先根据方法的参数 m 确定 g 和 p 的位置。将 g 移动到第一个要反转的节点的前面,将 p 移动到第一个要反转的节点的位置上。我们以 m=2,n=4为例。 2、将 p 后面的元素删除,然后添加到 g 的后面。也即头插法。 3、根据 m 和 n 重复步骤(2) 4、返回 dummyHead.next

代码

 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} left
 * @param {number} right
 * @return {ListNode}
 */
var reverseBetween = function(head, left, right) {
   // 定义虚拟头节点处理一个节点的特殊情况
let dummyHead = new ListNode(0, head);

// 定义双指针写法一: 
let g = dummyHead,
    p = dummyHead.next;
// 移动双指针到 g = left - 1, p = left 的位置
for (let i = 0; i < left - 1; i++) {
    g = g.next;
    p = p.next;
}

// 头插法处理
for (let i = 0; i < right - left; i++) {
    const removedNode = p.next;
    p.next = p.next.next;
    removedNode.next = g.next;
    g.next = removedNode;
}
return dummyHead.next;

};

先把那个反转链表1做一下, 那个题目搞懂了, 这个就很容易懂了 分三步走:

  1. 遍历到m的前一个位置 superior (因为需要遍历到前一个位置, 所以最好创建一个虚拟头结点)
  2. 定义一个节点使其指向m的位置 cur = superior.next 然后就是按照反转链表1的方式直接套就好了. 需要注意一下循环的边界 循环结束之后, 脑海中要浮现出三个指针的位置(浮现个屁, 用纸笔画一下吧骚年) prev 指向n-m的位置,也就是最后一个旋转的节点 cur和next都指向n-m的下一个位置
  3. 最后调整一下superior.next(m处的节点)和prev(n-m位置处)这两个节点的指向即可