【前端面试常见算法题系列】206. 反转链表

171 阅读3分钟

“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

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

二、思路分析

题意要求我们用迭代或递归方式完成反转,那么我们就来看看如何达到这个要求。

以示例1举例子:head = [1,2,3,4,5]

先来看看迭代的思路:
要让 1->2 这节链表实现反转,变成 2->1 ,肯定是先获取到 2 这个节点,然后将 next 指针指向 1 ,然而这里有一个问题:当我们获取到 2 节点后,已经不能获取 1 节点了,因此我们需要想办法获取 1 节点(怎么搞的,要我获取 2 节点的是你,现在要获取 1 节点的也是你,到底想怎么样)。哈哈,其实很容易解决,我们可以先定义一个全局变量 ans ,在处于 1 节点的时候,将其保存下来,那么当 2 节点需要修改 next 指向为 1 时,指向 ans 就好啦。解决这个之后,事情就好办了,按照这个流程一直下去,知道 headnullptr 即可完成反转了。

注意:反转前的 head 最后是指向 nullptr 的,因此反转链表之后,最后的指针也要指向 nullptr ,因此一开始的 ans 变量自然而然要赋值为 nullptr ,并且遍历到链表的第一个节点时顺便修改其 next 指向为 ans

再来看看递归的思路:
这里换一种思路,先给出答案,再讲解为什么是这个答案

ListNode* reverseList(ListNode* head) {
    if (head == nullptr || head -> next == nullptr) return head;
    ListNode* cur = reverseList(head -> next);
    head -> next -> next = head;
    head -> next = nullptr;
    return cur;
}

同样以 head=[1, 2, 3, 4, 5] 为例,链表进入递归函数 reverseList 之后,head 会一直遍历下去,直到链表末尾也就是值为 5 ,发现满足条件 head -> next == nullptr ,于是被 return结果 head 变回 4,这时候就需要开始进行反转了(终于可以执行第二行之后的代码了呀,真是不容易),仔细看看 head -> next -> next = head 这行代码,我将其拆开来:head(也就是4)-> next == 55 -> next(修改5的next指针)== head(4),这样一来原本 4->5 的指向关系就变更为 5->4 了;然后是 head -> next == nullptr4next 被指向 nullptr ,其实这里指向哪里无所谓,反正待会还是会被第三行代码修改指向,只是最后整个链表要指向 nullptr ,因此这里就写成指向 nullptr

注意:递归做法不要陷进循环里,搞清楚一个递归过程就可以了,其他递归也是一样的过程啊。

三、AC 代码

链表定义如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */

方法一:迭代法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* ans = nullptr;
        while (head) {
            head -> next = ans;
            ans = head;
            head = head -> next;
        }
        return ans;
    }
};

方法二:递归法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == nullptr || head -> next == nullptr) return head;
        ListNode* cur = reverseList(head -> next);
        head -> next -> next = head;
        head -> next = nullptr;
        return cur;
    }
};