「前端刷题」206.反转链表(EASY)

579 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

题目(Reverse Linked List)

链接:https://leetcode-cn.com/problems/reverse-linked-list
解决数:9798
通过率:73.2%
标签:递归 链表 
相关公司:bytedance amazon microsoft 

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

 

示例 1:

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

示例 2:

输入: head = [1,2]
输出: [2,1]

示例 3:

输入: head = []
输出: []

 

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

 

进阶: 链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

思路

迭代

  • 关键
    • 将当前节点的指针指向上一个节点
    • 然后更新当前节点和下一个节点的值即顺移
  • 技巧
    • 设置哨兵节点 null,初始化时将head节点指向null,下一步将next指向head
    • 重复以上动作直到当前节点为尾节点的节点null
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let prev = null;
    let curr = head;
    while(curr != null){
        let next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
};

尾递归

  • 其实就是解法一的简化版
    • prev = curr;
      curr = next;

  • 此解法将 上面放在递归里返回
    • 同理都是做将当前节点指向前一个节点的操作之后,来顺移更新前一个、当前、和下一个节点的操作
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let reverse = (prev,curr) => {
        if(!curr)return prev;
        let next = curr.next;
        curr.next = prev;
        return reverse(curr,next);
    }
    return reverse(null,head);
};

递归

  • 关键是反转操作
    • 当前节点 head,下一个节点 head.next
    • head.next.next = head
      • 此处将原 head.next 指向head,即是反转
    • head.next = null
      • 此处将原 head 指向head.next的指针断开
  • 递归
    • 由编译器函数调用执行栈原理可知
      • 最先调用的函数会在递归过程中最后被执行,而最后调用的会最先执行
    • 因此此题,最先返回最后两个节点开始反转操作
      • 依次从后面两两节点开始反转
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    // 如果测试用例只有一个节点 或者 递归到了尾节点,返回当前节点 
    if(!head || !head.next) return head;
    // 存储当前节点的下一个节点
    let next = head.next;
    let reverseHead = reverseList(next);
    // 断开 head ,如图闪电⚡️标记处
    head.next = null;
    // 反转,后一个节点连接当前节点
    next.next = head;
    return reverseHead;
};

栈解

  • 既然是反转,那么符合栈先进后出的特点
  • 将原节点依次入栈
  • 出栈时,重新构造链表改变指向
  • 同样设置哨兵节点
    • 最后返回哨兵的next即为所求
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var reverseList = function(head) {
    let tmp = head;
    let tHead = new ListNode(0);
    let pre = tHead;
    let stack = [];
    while(tmp){
        stack.push(tmp.val);
        tmp = tmp.next;
    }
    while(stack.length != 0){
        pre.next = new ListNode(stack.pop());
        pre = pre.next;
    }
    return tHead.next;
};