[前端]_一起刷leetcode 92. 反转链表 II

271 阅读2分钟

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

题目:

92. 反转链表 II

给你单链表的头指针 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]

 

提示:

  • 链表中节点数目为 n
  • 1 <= n <= 500
  • -500 <= Node.val <= 500
  • 1 <= left <= right <= n

 

进阶:  你可以使用一趟扫描完成反转吗?

思路:

  1. 为了避免判断是否从头部开始反转,给链表头部插入一个节点result, result的下一个节点指向头节点;
  2. 把链表拆成三段, 中间是要反转的数据, 头部和尾部不用做处理;
  3. 找到反转的起点cur,让它停留在那个位置,找个代跑temp替它往后遍历。 然后对中间数据进行一个反转, 不懂如何反转整个链表的可以看一下我这篇文章 # [路飞]_一起刷leetcode 206. 反转链表
  4. 反转前记得记录中间数据的头节点last,待会儿它反转后就是尾节点;
  5. 反转完成。记录中间链表的头节点prev, 和当前反转完成后,尾部头节点temp;
  6. 让头部的末尾节点,链接中间的头节点,即: cur.next = prev;
  7. 让中间的末尾节点,链接尾部的头节点,即: last.next = temp;
  8. 返回我们插入的头节点的下一个节点result.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) {
    // 如果要反转的片段是同个节点,那就不用转了
    if (left === right) {
        return head;
    }

    // 为了防止需要从头节点开始转,需要特殊处理, 所以在头节点前面插入一个元素
    let result = new ListNode(0, head);
    // 需要返回全部链表,所以需要找个代跑
    let cur = result;

    // 找到开始反转的节点
    while (left > 1) {
        cur = cur.next;
        left--;
        right--;
    }

    // 找个代跑。保留切割的位置。待会儿这个切割位next指向反转后的头节点
    let temp = cur.next;
    // 记录当前要反转的头节点,它是待会儿反转后的尾节点,链接尾部即可
    let last = cur.next;
    let prev = null;

    // 反转中间的链表
    while (right > 0) {
        const next = temp.next;
        temp.next = prev;
        prev = temp;
        temp = next;
        right--;
    }

    // 反转结束,这时候把前半截和中间反转的这截链接
    cur.next = prev;
    // 中间反转的这截和尾部链接
    last.next = temp;

    return result.next;
};

看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。