【刷题之路】LeetCode 206. 反转链表
- 一、题目描述
- 二、解题
- 1、方法1——改变指针方向
- 1.1、思路分析
- 1.2、代码实现
- 2、方法2——头插到新链表
- 2.1、思路分析
- 2.2、代码实现
一、题目描述
原题连接: 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
二、解题
1、方法1——改变指针方向
1.1、思路分析
因为链表的节点在内存中的地址是随机的,它们之间的联系方式只是通过一个next指针来联系:
所以我们其实只需要将各个节点之间的指针的方向反转过来,然后再将第一节点的next置为NULL将最后一个节点当做新的头节点即可:
而因为单链表的局限性,我们想要完成翻转就必须使用三个指针,pre、cur、next辅助反转,如下图所示:
只有这样我们才能做到在翻转cur的next方向时候,既能找到cur的前一个节点,也能保证在反转之后找到cur的下一个节点:
翻转完一个节点后,我们就让pre = cur,cur = next,next = next->next,就这样一直迭代地往后走就行了:
对后当cur为NULL时,就说明了我们已经把链表中所有的节点的指针方向全都反转过来了,所以结束条件就是cur为NULL:
所以我们之后返回pre作为新的头节点即可。
1.2、代码实现
有了以上思路,那我们写起代码来也就水到渠成了:
struct ListNode* reverseList(struct ListNode* head){
if (NULL == head) {
return NULL;
}
struct ListNode *Pre = NULL;
struct ListNode *Cur = head;
struct ListNode *Next = head->next;
while (Cur) {
// 翻转
Cur->next = Pre;
// 迭代
Pre = Cur;
Cur = Next;
if (Next) {
Next = Next->next;
}
}
return Pre;
}
时间复杂度:O(n),n为链表的长度。
空间复杂度:O(1),我们只需要用到常数级的额外空间。
2、方法2——头插到新链表
2.1、思路分析
还有一个更简洁的方式就是将原链表中的节点按顺序头插到一个新的链表中,这样当我们头插完所有的节点得到的新链表也就是翻转完成后的链表:
同样的,我们还是需要两个指针cur和next来帮我们完成头插,在每次将cur头插到新链表之前,先让next保存cur的下一个节点:
最后我们返回新的头指针newhead即可。
2.2、代码实现
有了以上思路,那我们写起代码来也就水到渠成了
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* Cur = head;
struct ListNode* newhead = NULL; // 新的头指针
struct ListNode* Next = NULL; // 保存cur的下一个节点,以辅助头插
while (Cur) {
Next = Cur->next;
// 头插
Cur->next = newhead;
newhead = Cur;
// 迭代往后走
Cur = Next;
}
return newhead;
}
时间复杂度:O(n),n为链表的长度。
空间复杂度:O(1),我们只需要用到常数级的额外空间。