[路飞]_92-反转链表 II

298 阅读2分钟
  • 题目描述
    • 给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。   示例1:

fz1.png

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

解题思路

  1. 找到 left 和 right 两个节点,并且记录 left 的前节点为 prevLeft,right 的下个节点为 rightNext

    • 从 head 往右走 left - 1 步就是 left
    • 从 left 往右走 right - left 步就是 right
  2. 找到 left 、right 后,把 left 的下个节点至 right 的前个节点进行翻转

    • curr 指向 left,从 left 开始翻转
    • prev 指向 rightNext,这样翻转子链表时,头节点正好和后半段连接上
    • 定义好 curr、prev 就可以对子链表进行翻转了
  3. 翻转完子链表后把前半段和子链表的头拼接上,即 preLeft.next = rightNode

  4. 返回 head

var reverseBetween = function(head, left, right) {
  if (!head || !head.next || left === right) return head

  let curr = head
  let prev = next = null
  let leftNode = prevLeft = rightNode = rightNext = null
  
  //找到 left 要走的步数
  let step = left - 1

  //找到第 left 个节点,和 left前一个节点
  while (step--) {
    prevLeft = curr
    curr = curr.next
  }
  leftNode = curr
  prevLeft.next = null

  //找到第 right 个节点,和 right 的下一个节点
  step = right - left
  while (step--) {
    curr = curr.next
  }
  rightNode = curr
  rightNext = curr.next
  rightNode.next = null

  //翻转 left 至 right 之间的子链表
  curr = leftNode
  prev = rightNext

  while (curr) {
    next = curr.next
    curr.next = prev
    prev = curr
    curr = next
  }

  //把子链表和前半段拼接
  prevLeft.next = rightNode

  return head
}

第二种写法

var reverseBetween = function (head, left, right) {
    if(head == null) return null
    // new ListNode(-1) 代表下标从链表头结点的前一位开始
    let ret = new ListNode(-1,head),pre = ret,cnt = right - left +1;
    while(--left){ // --left 代表left有几个就运行几次 例如3:就运行3次
        pre = pre.next;
    }
    pre.next = reverse(pre.next,cnt);
    return ret.next;
};

var reverse = function(head,n){
    let pre = null,cur = head;
    while(n--){ // n-- 代表 n 少运行一次 例如3:就运行2次
        [cur.next,pre,cur] = [pre,cur,cur.next]
    }
    head.next = cur;
    return pre;
}

欢迎三连讨论