【路飞】leetcode-206.反转链表

156 阅读2分钟

加油 第 4、5 练

206. 反转链表

题目描述:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

方法一:递归

var reverseList = function(head) {
    if (head == null || head.next == null) {
        return head;
    }
    //递归的传入下一个节点 - 到最后一个节点返回
    const newHead = reverseList(head.next);
    /**
     * 以1,2,3,4,5为例
     * 第一轮head为5,head.next为空,返回5
     * 第二轮head为4,head.next为5,执行head.next.next=head也就是5.next=4,
                      把当前节点的子节点的子节点指向当前节点
                      此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
                      此时链表为1->2->3->4<-5
                      返回节点5
     *  第三轮,head为3,head.next为4,执行head.next.next=head也就是4.next=3,
                      此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
                      此时链表为1->2->3<-4<-5
                      返回节点5
     * 第四轮,head为2,head.next为3,执行head.next.next=head也就是3.next=2,
                      此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
                      此时链表为1->2<-3<-4<-5
                      返回节点5
     * 第五轮,head为1,head.next为2,执行head.next.next=head也就是2.next=1,
                      此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
                      此时链表为1<-2<-3<-4<-5
                      返回节点5
     * 出栈,最终头节点5->4->3-2->1
     */
    head.next.next = head;
    // 当链表递归反转之后,新的头节点是last,
    //而之前的head变成了最后一个节点,链表的末尾要指向 null
    head.next = null;
    return newHead;
};

//思考: new ListNode
var  ans = null;
for ( let x = head; x != null; x = x.next) {
    ans = new ListNode(x.val,ans);
}
return ans;

//类似[].reverse()
var reverse = function(pre, head) {
    if(!head) return pre;
    const temp = head.next;
    head.next = pre;
    pre = head
    return reverse(pre, temp);
}
 return reverse(null, head);
 
 // 递归2
var reverse = function(head) {
    if(!head || !head.next) return head;
    // 从后往前翻
    const pre = reverse(head.next);
    head.next = pre.next;
    pre.next = head;
    return head;
}

var reverseList = function(head) {
    let cur = head;
    while(cur && cur.next) {
        cur = cur.next;
    }
    reverse(head);
    return cur;
};

方法二:指针

  • 定义三个指针“前指针pre”、“当前指针cur”、“后指针next”
  • 指针每次移动反向修改当前节点cur链表指针指向prev
  • 修改节点完成后,更新prev和cur指针
  • 最后返回prev,即可获得整条反向链表
var reverseList = function(head) {
  let prev = null,cur = head,next = head;
  while (cur) {
    next = cur.next;
    cur.next = prev;
    prev = cur;
    cur = next;
    //ES6解构赋值,curr.next和prev反向
    //[curr.next, prev, curr] = [prev, curr, curr.next];
  }
  return prev;
};

92. 反转链表 II

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

image.png

方法一

切断left到right的链表,反转之(反转方法同上),再反转连接。
(切断连接,区间反转,反向连接)

 var reverseBetween = function(head, left, right) {
    const _Node = new ListNode(-1);
    _Node.next = head//虚拟头节点

    let pre = _Node
    for (let i = 0; i < left - 1; i++) {
        //pre遍历到left的前一个节点
        pre = pre.next
    }
    let rightNode = pre
    for (let i = 0; i < right - left + 1; i++) {
        //rightNode遍历到right的位置
        rightNode = rightNode.next
    }
    let leftNode = pre.next //保存leftNode
    let curr = rightNode.next //保存rightNode.next
    //切断left到right链,独立出区间
    pre.next = null
    rightNode.next = null

    var reverseList = function(head) {
        let prev = null,curr = head;
        while (curr) {
          [curr.next, prev, curr] = [prev, curr, curr.next];
        }
      };
    
      reverseList(leftNode);

    //   反向连接
      pre.next = rightNode;
      leftNode.next = curr;

      return _Node.next;
};
方法二:

遍历到left的前一个节点,由该节点开始反转到right区间内的链表(无需切断再连接)

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

   // 遍历到开始反转的前一个节点(left的前一个节点)
   let pre = _node;
   for (let i = 0; i < left - 1; ++i) {
       pre = pre.next;
   }
   //  left到right区间反转
   let curr = pre.next;
   for (let i = 0; i < right - left; ++i) {
        const next = curr.next;
        curr.next = next.next;
        next.next = pre.next;
        pre.next = next;
    }
    return _node.next;
};