代码随想录 第二章 链表 206. 反转链表
题目:206. 反转链表
- 题目描述:给你单链表的头节点
head ,请你反转链表,并返回反转后的链表。
一、思想
以下是链表反转过程的详细步骤表格,以链表 1 -> 2 -> 3 -> 4 -> 5 -> nullptr 为例:
| 步骤 | pre 指针 | cur 指针 | tmp 指针 | 操作描述 | 链表状态(反转后) |
|---|---|---|---|---|---|
| 初始 | nullptr | 1 | nullptr | 初始化 pre 和 cur 指针 | 1 -> 2 -> 3 -> 4 -> 5 -> nullptr |
| 1 | nullptr | 1 | 2 | 保存 cur->next 到 tmp | 1 -> 2 -> 3 -> 4 -> 5 -> nullptr |
nullptr | 1 | 2 | 将 cur->next 指向 pre | 1 -> nullptr | |
1 | 2 | 2 | 移动 pre 到 cur,cur 到 tmp | 1 -> nullptr | |
| 2 | 1 | 2 | 3 | 保存 cur->next 到 tmp | 2 -> 3 -> 4 -> 5 -> nullptr |
1 | 2 | 3 | 将 cur->next 指向 pre | 2 -> 1 -> nullptr | |
2 | 3 | 3 | 移动 pre 到 cur,cur 到 tmp | 2 -> 1 -> nullptr | |
| 3 | 2 | 3 | 4 | 保存 cur->next 到 tmp | 3 -> 4 -> 5 -> nullptr |
2 | 3 | 4 | 将 cur->next 指向 pre | 3 -> 2 -> 1 -> nullptr | |
3 | 4 | 4 | 移动 pre 到 cur,cur 到 tmp | 3 -> 2 -> 1 -> nullptr | |
| 4 | 3 | 4 | 5 | 保存 cur->next 到 tmp | 4 -> 5 -> nullptr |
3 | 4 | 5 | 将 cur->next 指向 pre | 4 -> 3 -> 2 -> 1 -> nullptr | |
4 | 5 | 5 | 移动 pre 到 cur,cur 到 tmp | 4 -> 3 -> 2 -> 1 -> nullptr | |
| 5 | 4 | 5 | nullptr | 保存 cur->next 到 tmp | 5 -> nullptr |
4 | 5 | nullptr | 将 cur->next 指向 pre | 5 -> 4 -> 3 -> 2 -> 1 -> nullptr | |
5 | nullptr | nullptr | 移动 pre 到 cur,cur 到 tmp | 5 -> 4 -> 3 -> 2 -> 1 -> nullptr | |
| 结束 | 5 | nullptr | nullptr | 反转完成,返回 pre | 5 -> 4 -> 3 -> 2 -> 1 -> nullptr |
二、代码
/**
* 定义一个Solution类,包含一个反转链表的函数reverseList
*/
class Solution
{
public:
/**
* 函数功能:反转一个单链表
* 参数:head,链表的头节点
* 返回值:反转后的链表的头节点
* 说明:本题不使用虚拟头节点的原因:
* 1. 反转操作只需改变指针方向,无需插入新节点
* 2. 使用虚拟头节点会增加额外空间复杂度
* 3. 空链表情况已通过while(cur)判断处理
* 4. 直接操作原链表指针更简洁高效
*/
ListNode *reverseList(ListNode *head)
{
// 初始化当前节点为头节点,前一个节点为空,临时节点用于保存当前节点的下一个节点
ListNode *cur = head;
ListNode *pre = nullptr;
ListNode *tmp;
// 当当前节点存在时,执行循环
while (cur) {
// 保存当前节点的下一个节点
tmp = cur->next;
// 将当前节点的next指针指向前一个节点
cur->next = pre;
// 将前一个节点更新为当前节点
pre = cur;
// 将当前节点更新为临时节点
cur = tmp;
}
// 返回反转后的链表的头节点
return pre;
}
};
三、代码解析
1. 算法工作原理分解
-
初始化指针:
-
cur 指针指向链表的头节点,用于遍历链表。 -
pre 指针初始化为nullptr,用于记录当前节点的前一个节点。 -
tmp 指针用于临时保存当前节点的下一个节点。
-
-
反转过程:
- 保存下一个节点:在每次循环中,首先使用
tmp 指针保存cur->next 节点,因为接下来要改变cur->next 的指向。 - 反转当前节点:将
cur->next 指向pre,完成当前节点的反转。 - 移动指针:将
pre 指针移动到cur 的位置,cur 指针移动到tmp 的位置,继续处理下一个节点。
- 保存下一个节点:在每次循环中,首先使用
-
循环处理:
- 重复上述步骤,直到
cur 指针指向nullptr,表示链表已经遍历完毕。
- 重复上述步骤,直到
-
返回结果:
- 当
cur 指针指向nullptr 时,pre 指针指向新的头节点,返回pre 即可。
- 当
2. 关键点说明
-
tmp 指针的作用:保存当前节点的下一个节点,因为在反转当前节点后,cur->next 会被改变,如果不保存,就无法继续遍历链表。 -
pre 指针的作用:记录当前节点的前一个节点,用于反转操作。 - 循环结束条件:当
cur 指针指向nullptr 时,表示链表已经遍历完毕,此时pre 指针指向新的头节点。
小结
- 直接操作原链表指针:代码更简洁、高效,且节省空间。
- 空链表情况已处理:通过
while(cur) 判断,直接返回pre,无需额外处理。
四、复杂度分析
-
时间复杂度:O(n)
- 我们需要遍历整个链表一次,因此时间复杂度为
O(n),其中n 是链表的长度。 - 在最坏情况下,链表中所有节点都需要反转,但时间复杂度仍然是
O(n),因为每个节点只需处理一次。
- 我们需要遍历整个链表一次,因此时间复杂度为
-
空间复杂度:O(1)
- 我们只使用了常数级别的额外空间(
cur、pre 和tmp 指针),因此空间复杂度为O(1)。 - 无论链表的长度如何,我们使用的额外空间都是固定的,与链表长度无关。
- 我们只使用了常数级别的额外空间(

377

被折叠的 条评论
为什么被折叠?



