定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000
注意:本题与主站 206 题相同:https://leetcode-cn.com/problems/reverse-linked-list/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
}
};
题解一
在遍历链表时,将当前节点的 \textit{next}next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。
#include <iostream>
using namespace std;
//Definition for singly - linked list.
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};
/*打印链表*/
void printList(ListNode* head)
{
ListNode* phead = head;
while (phead != NULL)
{
cout << phead->val << " ";
phead = phead->next;
}
cout << "\n";
}
int main()
{
//链表赋值
int a[5] = {1,2,3,4,5};
ListNode *La = new ListNode(a[0]);
ListNode* phead = La;
for (int i = 1; i < 5; i++)
{
ListNode* newnode = new ListNode(a[i]);
phead->next = newnode;//并将其赋值给La
phead = newnode;
} //链表赋值
Solution sln;
printList(La);
ListNode* Lc = sln.reverseList(La);
printList(Lc);
return 0;
}
复杂度分析
-
时间复杂度:O(n),其中 n 是链表的长度。需要遍历链表一次。
-
空间复杂度:O(1)。
好理解的双指针
定义两个指针: prepre 和 curcur ;prepre 在前 curcur 在后。
每次让 prepre 的 nextnext 指向 curcur ,实现一次局部反转
局部反转完成之后, prepre 和 curcur 同时往前移动一个位置
循环上述过程,直至 prepre 到达链表尾部
解题二
简洁的递归
使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作 retret .
此后,每次函数在返回的过程中,让当前结点的下一个结点的 nextnext 指针指向当前节点。
同时让当前结点的 nextnext 指针指向 NULLNULL ,从而实现从链表尾部开始的局部反转
当递归函数全部出栈后,链表反转完成。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL || head->next == NULL) {
return head;
}
ListNode* ret = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return ret;
}
};
解题三
妖魔化的双指针
原链表的头结点就是反转之后链表的尾结点,使用 headhead 标记 .
定义指针 curcur,初始化为 headhead .
每次都让 headhead 下一个结点的 nextnext 指向 curcur ,实现一次局部反转
局部反转完成之后,curcur 和 headhead 的 nextnext 指针同时 往前移动一个位置
循环上述过程,直至 curcur 到达链表的最后一个结点 .
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL) { return NULL; }
ListNode* cur = head;
while (head->next != NULL) {
ListNode* t = head->next->next;
head->next->next = cur;
cur = head->next;
head->next = t;
}
return cur;
}
};
面试官给了一张白纸,然后直接手写了一道题:反转链表
就4个字,不像leetcode上面还有输入输出示例,以及最关键的链表的结构:链表用一个结构体表示,包含两个成员值val和指针next,以及一个构造函数。