[LeetCode-92反转链表II] | 刷题打卡

313 阅读2分钟

掘金团队号上线,助你 Offer 临门! 点击 查看详情

题目描述

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

示例1:

rev2ex2.jpeg

解题思路

两种方式: 因为两种方式都用到了虚拟头节点,也是俗称的哨兵,在这道题目中虚拟头节点的作用是方便对链表的特殊操作进行处理,所有有可能操作到链表头节点的操作,都可以设置一个虚拟头节点。

一:迭代法,上次给过反转链表的动态图示了,可以举一反三,这次口述步骤:

  1. 首先我们定义一个虚拟头节点,起名叫做ret,将它指向我们的真实头节点。
  2. 定义一个节点p = ret。
  3. 我们需要根据left找到带反转区域的头节点
  4. 接下来就是和206反转链表的思路一致了,只不过这里的循环终止条件需要依赖反转区域节点的总数,在循环结束时也不能直接返回pre,这样会丢失掉未反转部分的节点,所以区间反转过后,需要将原来的head头节点(也就是反转过后的尾节点)指针指向cur
  5. 后面就是执行我们定义的reverseList1函数,返回ret.next(虚头的next指向原链表头节点)

二: 递归:递归的函数用reverseList表示,递归方式符合进阶,只用了一次迭代,和206反转链表的不同点也是递归的终止条件,同样也需要注意下,不要丢失原链表节点。

解题代码

// 迭代封装的方法
var reverseList1 = function (head, n) {
    let [pre, cur] = [null, head];
    while (n--) {
        [cur.next, pre, cur] = [pre, cur, cur.next];
    }
    head.next = cur;
    return pre;
}

var reverseList = function (head, n) {
    if (n === 1) return head;
    let tail = head.next, p = reverseList(head.next, n - 1);
    head.next = tail.next;
    tail.next = head;
    return p;
}

var reverseBetween = function (head, left, right) {
    let cnt = right - left + 1;
    let ret = new ListNode(0, head), p = ret;
    while (--left) p = p.next;
    // p.next = reverseList(p.next, cnt);
    p.next = reverseList1(p.next, cnt);
    return ret.next;
};

总结

最近学了链表这种数据结构,为了巩固,目前几篇都是专攻链表方面的算法题,如果文中有错误,忘指出。