问题描述
给你单链表的头节点 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
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
解题思路
迭代的方法反转链表,比较暴力的方式是不断遍历链表最后然后逐个向前,但是那样太浪费时间啦,我们可以从新链表的最后一个节点向前走。
我使用三个变量p q r,分别依次指向链表中的节点,默认情况下p节点已经是反转后的节点了,然后在while循环中只要r!=NULL,我们就一直让q也反转指向p,然后更新变量,p q r沿着原链表向右挪一个位置,然后继续。最后退出循环只需使q指向p,然后返回q即可。
递归的方法的话,使用的是从原链表的最后向前逐个连接。
设想该函数的功能是返回反转后链表的头节点,然后在该函数内对原链表head之后的节点都已反转完毕,则这就是递归函数的主要功能,然后我们只需增加细节,判断临界情况即可。
若head即为NULL,则为空链表,直接返回NULL就行。还有一个判断条件head->next==NULL,这个条件有两个作用,一是链表为单链表,二为递归的调用函数到链表最后时,由于需要返回反转后链表的头节点,所以需要返回原链表的最后一个。
然后对于当前的head节点,head->next指反转后链表的最后一个,然后再->next指向head,即可完成该节点处的反转,然后使head指向NULL,最后返回head之后已反转之后链表的头节点。
解题代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
///
//迭代的方法反转链表
///
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* p = head;
//该if是为了判断空链表的情况
if (p == NULL) {
return p;
}
struct ListNode* q = p->next;
//该if是为了判断链表中只有一个节点的情况
if (q == NULL) {
return p;
}
p->next = NULL;
struct ListNode* r = q->next;
//while循环迭代的反转链表,直到r为空
while (r != NULL) {
q->next = p;
p = q;
q = r;
r = r->next;
}
//r为空,只需使q指向p,此时整个链表已经反转完成,返回头节点q即可
q->next = p;
return q;
}
///
//递归的方法
///
struct ListNode* reverseList(struct ListNode* head) {
if (head == NULL) {
return NULL;
}
if (head->next == NULL) {
return head;
}
struct ListNode* newhead = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return newhead;
}