一、题目
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
更多细节请参看官方题目详情。
二、题解
2.1 迭代法
| 1 --> | 2--> | 3 --> | 4--> | 5 | |||
|---|---|---|---|---|---|---|---|
| head | |||||||
| head->next |
对于一个链表,已知头节点,我们只知道头节点和头节点的下一个节点。
现在要实现链表的反转, 我们可以先创建一个链表 ListNode *pre = nullptr;,然后不断遍历当前链表的节点,使其指向 pre
| 1 --> | 2--> | 3 --> | 4--> | 5--> | nullptr | ||
|---|---|---|---|---|---|---|---|
| head | head->next | ||||||
| ListNode *pre = nullptr | <-- cur | ||||||
| <-- (cur->next) |
链表反转通常需要用到三个指针:
- 当前节点指针 cur,需要连接前一个节点,原来的首节点应该连接 nullptr 节点
- 前驱节点指针 pre,上一步连接完成,应该让pre指针指向cur
- 后继节点指针 在上两个步骤开始之前应该最先记录当前节点的后继节点,便于找到更新前的cur-->next,看下面的图,我们就会清楚的知道一旦当前节点指向前一个节点,当前节点和原来的下一个节点的连接就断了,所以我们应该提前记录一下当前节点的下一个节点,以便cur节点重新指向pre的时候,还能找到之后要遍历的节点。
//初始化
pre = nullptr;
cur = head;
//记录后继系节点
after = cur->next;
在反转链表的过程中,当前节点指针指向的节点的 next 指针需要指向其前驱节点,因此需要在遍历链表的同时记录当前节点指针和前驱节点指针。由于链表是单向的,需要用到后继节点指针来记录下一个要遍历的节点。
/**
* 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* pre = nullptr;
ListNode* cur = head;
while(cur != nullptr)
{
ListNode* after = cur->next;
cur->next = pre;
pre = cur;
cur = after;
}
return pre;
}
};
2.2 递归法
我理解的递归法的思路就是找一样的,可以重复处理的步骤,再确定好终止条件就可以了。
其他节点的操作都一样只要当前节点,和下一个节点不为空,就可以继续操作;也就是只要当前节点,和下一个节点为空就终止。否则递归处理当前节点的下一个节点recursive(head->next)。
或者可以理解为,head指针到达链表的尾部,开始向前逐个反转,但是过程中需要 如果nk以后的节点都已经完成反转操作,那么该如何处理,nk到nk-1以前的节点呢?
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
}
};
三、总结
| 题目 | 知识点 | 进度 |
|---|---|---|
| 136 | 数组、位运算(异或)、哈希表 | 1 |
| 121 | 数组、动态规划 | 2 |
| 3 | 字符串、滑动窗口、哈希表 | 3 |
| 131 | 字符串、回溯、动态规划 | 4 |
| 206 | 递归、链表 | 6 |