js算法题解(第十三天)---92. 反转链表 II

167 阅读3分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战

前言

死磕算法,每天至少完成一道算法题

今天咱们来做一下反转链表的升级版,昨天的反转链表想必大家都理解的七七八八了,今天咱们在突破一下这个中等题目(看到中等题目,大家要兴奋哦)

题目

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

image.png

示例 1:

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

思路

  • 1.其中 left <= right,所以有可能left=right,这个咱们要判断的

分析

  • 1.我们先自己画图,画图后就会发现,纯手工画图,哈哈😝

图片.png

  • 2.我们要反转的是2到4,但是我们反转后,1早忘了,所以我们先把1存储起来,(这里的诀窍就是把遍历过的节点,但是后面要改变指针的节点先保存起来)再看一下还有谁后面要改变指针,还有2,所以我们开始动手吧

我们先写框架

var reverseBetween = function(head, left, right) {
    // 此处我们考虑一下left===right
    if(!head||!head.next||left===right){
        return head;
    }
    let dummy = new ListNode();
    dummy.next = head;
    // 声明要保存的节点
    let pre,cur,leftHead,start;

    return dummy.next;
};

接下来就是拿到leftHead,也就是左侧反转区间前的一个节点

   // 定义一个哨兵,dummy代表着i=0;反转的时候都是从dummy开始的
   let p = dummy.next;
    // 因为是区间前面,所以left-1
   for(let i=1;i<left-1;i++){
       // 循环大家写了很多遍了,相信大家都会了
       p = p.next;
   }
   leftHead = p;

再接下来我们保存反转区间的第一个元素,也就是leftHead.next

start = leftHead.next;

然后开始反转,反转如反转链表I的写法一样

 pre = start;
    cur = pre.next;
    // 我们反转left到right区间内的数字
    for(let i=left;i<right;i++){
        let next = cur.next;
        // 开始反转,当前节点的next指向前一个节点
        cur.next = pre;
        pre = cur;
        cur = next;
    }

此时的pre就是反转后的结果

 // 改变1的指向
    leftHead.next = pre;
    // 改变start的指向,上面遍历结束以后,我们发现cur正好指向5,所以
    start.next = cur;

题解

/**
 * @param {ListNode} head
 * @param {number} left
 * @param {number} right
 * @return {ListNode}
 */
var reverseBetween = function(head, left, right) {
    // 此处我们考虑一下left===right
    if(!head||!head.next||left===right){
        return head;
    }
    let dummy = new ListNode();
    dummy.next = head;
    // 声明要保存的节点
    let pre,cur,leftHead,start;
    // 接下来就是拿到leftHead,也就是左侧反转区间前的一个节点
    // 定义一个哨兵,dummy代表着i=0;反转的时候都是从dummy开始的
    let p = dummy;
     // 因为是区间前面,所以left-1
    for(let i=0;i<left-1;i++){
        // 循环大家写了很多遍了,相信大家都会了
        p = p.next;
    }
    leftHead = p;
    // 接下来我们保存反转区间的第一个元素,也就是leftHead.next
    start = leftHead.next;
    // 然后开始反转,反转如反转链表I的写法一样
    pre = null;
    cur = leftHead.next;
    // 我们反转left到right区间内的数字
    for(let i=left-1;i<right;i++){
        let next = cur.next;
        // 开始反转,当前节点的next指向前一个节点
        cur.next = pre;
        pre = cur;
        cur = next;
    }
    // 改变1的指向
    leftHead.next = pre;
    // 改变start的指向,上面遍历结束以后,我们发现cur正好指向5,所以
    start.next = cur;


    return dummy.next;
};

总结

  • 1.一定要先画图,真的链表题的诀窍就是先画图,一步步把结果画出来
  • 2.我们遍历过得节点,如果后面用的到的话,那么先保存起来

参考

92. 反转链表 II 前端算法与数据结构面试:底层逻辑解读与大厂真题训练