反转链表

75 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

题目描述


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

示例 1:

image.png

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

示例 2:

image.png

输入:head = [1,2] 输出:[2,1] 示例 3:

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

提示:

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

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


题目解释

链表:N1->N2->N3->...->Nk->Nk+1->...->Nm

反链表 Nm->...->Nk+1->Nk->Nk-1->...->N3->N2->N1

解法1 迭代

迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果。

  1. 我们先存储next链表,每次循环,head = head.next 逐渐递减链表个数

但是head会变动。所以我们需要一个中间参数next,每次存储head.next,不参与head的变动。

  1. 用 pre 存储新的链表,每次把head->next 指向pre,即可反转成为当前节点的反转链表。

  2. pre = head pre 依旧是最新的链表

  • 注意 空链表 或者 只有一个节点的链表 则返回本身
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
 var reverseList = function(head) {
     //空链表 或者 只有一个节点的链表 则返回本身
     if(!head || !head.next){
         return head;
     }

    //反转链表
    let pre = next = null;
    while(head){
        next = head.next;
        head.next = pre;
        pre = head;
        head = next;
    }
    return pre;
};

image.png

解法2 递归

递归,就是在运行的过程中调用自己。

构成递归需具备的条件:

  1. 子问题须与原始问题为同样的事,且更为简单;

  2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理。

我们希望 Nk+1 的下一个节点指向 Nk,而  Nk+1 = Nk->next

所以 Nk->next->next = Nk

需要注意的是 N1 的下一个节点必须为 null 不然就会变成环。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
 var reverseList = function(head) {
    //空链表 或者 只有一个节点的链表 则返回本身
    if(!head || !head.next){
        return head;
    }

    const newHead = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return newHead;
};

image.png