# 反转链表II (opens new window)

  • 难度:Medium
  • 标签:链表反转 递归

# 刷题思路

  • [x] 迭代法
  • [x] 递归法

# 方法 1 迭代法

  • 思路: 区分前驱指针、反转部分、后续链表三个部分
  • 复杂度:
    • 时间 O(N). 一次遍历.
    • 空间 O(1)
  • 结果:
    • 执行用时:72 ms, 在所有 JavaScript 提交中击败了83.57%的用户
    • 内存消耗:37.5 MB, 在所有 JavaScript 提交中击败了5.03%的用户
var reverseBetween = function(head, m, n) {
    if (m === n) return head // 相等等于不反转
    const newHead = new ListNode(null)
    newHead.next = head
    // 前驱指针prev用于最后尾接"反转部分", 当前指针curr用于执行链表反转
    let [prev, curr] = [newHead, newHead.next]
    for (let i=1; i<m; i++) {
        prev = prev.next
        curr = curr.next
    }
    let res = null // 存储"反转部分"结果
    let currTail = curr // 存储初始 curr,反转后将成为"反转部分"的尾节点
    for (let i=m; i<=n; i++) {
        const next = curr.next
        curr.next = res
        res = curr
        curr = next
    }
    currTail.next = curr // "反转部分"尾接"后续链表"
    prev.next = res // 前驱指针尾接"反转部分"
    return newHead.next
};

# 方法 2 递归法

  • 复杂度:
    • 时间 O(N). 共计一次遍历.
    • 空间 O(N). 递归调用栈的消耗.
  • 结果:
    • 执行用时:80 ms, 在所有 JavaScript 提交中击败了60.11%的用户
    • 内存消耗:37.5 MB, 在所有 JavaScript 提交中击败了5.03%的用户
var reverseBetween = function(head, m, n) {
    if (!head || !head.next) return head
    if (m === 1) return reverseN(head, n)
    head.next = reverseBetween(head.next, m-1, n-1)
    return head
};

// 反转前N个节点
function reverseN (head, n) {
    if (n === 1) return head
    const res = reverseN(head.next, n-1)
    const next = head.next.next
    head.next.next = head
    head.next = next
    return res
}

JS刷题记录 Leetcode-js (opens new window) 每周都会更新刷题心得或者题解, 你的点赞或 star 都将助力我产出更好内容~