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
解法一:数组
思路:遍历链表将链表节点存储在数组中,从后向前遍历数组依次将节点翻转
代码如下:
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* arr[5001];
struct ListNode* p=head;
int i;
if(head==NULL){
return head;
}
for( i=0;p;i++){
arr[i]=p;
p=p->next;
}
int end=i-1;
for(i-=1;i>0;i--){
arr[i]->next=arr[i-1];
}
arr[0]->next=NULL;
return arr[end];
}
解法二:双指针
在这里要引入虚拟头节点的概念,在链表中对头节点的处理往往需要特殊对待,因此我们可以设置一个虚拟头节点,并让他指向实际头节点。这一步操作让头节点去特殊化,可以与普通节点共同处理。
- 首先定义三个指针pre,cur,next
- pre初始化为虚拟头节点
- cur初始化为实际头节点
- next负责记录cur后的节点(防止翻转后访问不到该节点)
- pre,cur,next为一个最小单位循环
- 第一步: 令cur->next=pre实现局部翻转
- pre,cur,next向后推一个节点
struct ListNode *reverseList(struct ListNode *head)
{
if (head == NULL || head->next == NULL)
{
return head;
}
struct ListNode *pre = NULL;
struct ListNode *cur = head;
struct ListNode *next = head->next;
while (next)
{
cur->next = pre;
pre = cur;
cur = next;
next = next->next;
}
cur->next = pre;
return cur;
}
解法三:递归
递归三要素:
- 递归终止条件:若参数节点不为NULL则将当前参数节点的后继节点传入递归函数中,一直到链表末尾
- 重复执行结构:将参数节点head后的节点翻转,即head->next->next=head
- 返回值:返回翻转后的链表头即原链表尾
struct ListNode *reverseList(struct ListNode *head) {
if (head == NULL ||head->next == NULL ) {
return head;
}
struct ListNode *ret = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return ret;
}
解法四:双指针妙用
思想:将pre指针的后继指向cur的后一个节点从而实现记录该节点的功能
struct ListNode *reverseList(struct ListNode *head) {
if (head == NULL || head->next == NULL) {
return head;
}
struct ListNode *pre = head;
struct ListNode *cur = head->next;
struct ListNode *next = cur->next;
while (next) {
cur->next = pre;
head->next = next;
pre = cur;
cur = next;
next = next->next;
}
head->next=NULL;
cur->next = pre;
return cur;
}