「前端刷题」92. 反转链表 II

119 阅读1分钟

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

题目

链接:leetcode-cn.com/problems/re…

给你单链表的头指针 head 和两个整数 leftright ,其中 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

递归的思路就是不断缩小问题的规模。

我们可以把left的位置逐步缩小到1,把此时left节点当作头节点,那么剩下的问题就是以left开头,反转前right个链表。
所以可以先实现一个反转前N个链表的函数,在将left===1时反转后的链表返回给上一层head.next。

代码

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     val: number
 *     next: ListNode | null
 *     constructor(val?: number, next?: ListNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.next = (next===undefined ? null : next)
 *     }
 * }
 */

// 反转前N个链表的函数
let s = null; // 可以理解为n+1之后的链表
function reverseN(node, n){
    if(n === 1){
        s = node.next;
        return node;
    }
    let last = reverseN(node.next, n-1); 
    node.next.next = node;
    node.next = s;
    return last;
}

function reverseBetween(head: ListNode | null, left: number, right: number): ListNode | null {
    
    // 当left等于1,那么就是反转以left开头,前right个链表。
    if(left === 1){
        return reverseN(head, right);
    }
    
    // 逐步缩小头节点left位置,当left缩小至1时,即为起点。
    // 在缩小头节点位置时,剩余链表长度也在缩小,所以right的位置也应当相应缩小。
    head.next = reverseBetween(head.next, left-1, right-1);

    return head;

};

思路2

rev2ex2.jpeg

  • 给定一个链表 头结点 head
  • 将链表 [left, right] 区间进行反转

本题 与「206. 反转链表」类似。

  • preleft 的上一个节点 ,[0 -> pre]本题是定点 不会根据结点反转变化对于结点的位置
  • cur 指向当前要翻转的链表结点
  • next cur的下一个结点

本题无需定义后继结点

var reverseBetween = function(head, left, right) {
     // 1
     const dummy_node = new ListNode(-1);
     dummy_node.next = head;

    // 2
    let pre = dummy_node;
    for (let i = 0; i < left - 1; ++i) {
        pre = pre.next;
    }
    //  3
    let cur = pre.next;
    for (let i = 0; i < right - left; ++i) {
         const next = cur.next;
         cur.next = next.next;
         next.next = pre.next;
         pre.next = next;
     }
     return dummy_node.next;
};
  1. 定义一个哑点,放在head前 (防止边界换位置问题)
  2. 寻找pre的位置,初始化位置是哑点位置
  3. 将cur的下一个结点插入到pre后面(right - left 次) cur位置每次反转以后会变化