LeetCode Hot 100——206.反转链表
206. 反转链表
题目描述
给你单链表的头节点 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
一、迭代法
这种方法的思想和数组中的交换元素有点类似,只不过对于单链表来说,是交换 next 指针。这种方法需要暂存指针防止被覆盖。反转后的尾节点是 NULL,将 prev 初始化为 NULL 并作为前驱节点(即临时保存的上一个节点),解决了单链表无法得到上一个节点地址的问题。
值得注意的是,这里的
head指的是第一个节点。所以返回的时候,prev也是第一个节点。
代码实现
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode *prev = NULL; // 前驱节点,初始为NULL(反转后变成尾)
struct ListNode *curr = head; // 当前节点
struct ListNode *next = NULL; // 临时保存下一个节点
while (curr != NULL) {
next = curr->next; // ① 先存下后面的路
curr->next = prev; // ② 掉头指向前一个
prev = curr; // ③ 前移
curr = next; // ④ 前移
}
return prev; // 循环结束,prev就是新链表的头
}
二、递归法
这个方法实际上会占比较多的空间,并且也有点不太好理解。
代码实现
struct ListNode* reverseList(struct ListNode* head) {
// 递归终止条件:空链表 或 只有一个节点,直接返回自身
if (head == NULL || head->next == NULL) {
return head;
}
// 递归反转 head 之后的子链表
struct ListNode *newHead = reverseList(head->next);
// 最难理解的一步:
// 此时 head->next 指向的是原链表中 head 的下一个节点(即反转后子链表的尾节点)
// 让这个尾节点的 next 指向 head,完成 head 的挂接
head->next->next = head;
// 将 head 的 next 置空,因为此时 head 应该变成新链表的尾节点
head->next = NULL;
return newHead; // 每一层递归都返回最顶层的 newHead(即原尾节点)
}
递归栈模拟
以 1 -> 2 -> 3 -> 4 为例:
reverseList(1) 调用 reverseList(2),一直压栈到 reverseList(4)。
reverseList(4) 触发终止条件,返回节点 4(此时 newHead = 4)。
回到 reverseList(3):head = 3,head->next = 4,执行 4->next = 3,3->next = NULL。返回 4。
回到 reverseList(2):head = 2,head->next = 3,执行 3->next = 2,2->next = NULL。返回 4。
回到 reverseList(1):head = 1,head->next = 2,执行 2->next = 1,1->next = NULL。返回 4。
最终链表变为 4 -> 3 -> 2 -> 1 -> NULL。

浙公网安备 33010602011771号