题目描述:
给你单链表的头节点 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 ?
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/reverse-linked-list 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
?
分析:
? ? ? ? 这道题让使用迭代和递归两种方法。
? ? ? ? 迭代思路应该好想一点,使用两个指针p1和p2,p1指向反转链表的头部,p2指向原链表的头部。p2从第二个节点依次后移,每当p2到达一个节点时,先记录下next=p2->next,然后断开p2与原链表的链接,把p2连接到p1前面,然后p1移动到新的反转链表头节点上,之后p2返回原链表,即p2=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) {
if(head==NULL) return NULL;
// p1指向新链表的头部
ListNode *p1=head;
// p2指向原链表的头部 初始情况下p1为新链表头部,故原链表头部可以理解为p1->next
ListNode *p2=p1->next;
// 遍历原链表
while(p2!=NULL)
{
// 记录p2在原链表的下个节点
ListNode *next=p2->next;
// 把p2链接到p1前面,作为反转后链表的新的头节点
p2->next=p1;
if(p1==head)
p1->next=NULL;
// p1移动到到新的头节点上
p1=p2;
// p2移动到原链表下一位
p2=next;
}
// 返回p1,即反转链表的头节点
return p1;
}
};
递归的方法,也容易想到。思路就是,对于当前节点head来说,使用递归函数f反转head->next之后的链表,然后把head挂到反转链表的最后一个节点即可。但是有个问题:递归函数返回的指针,究竟是应该指向反转链表的头节点,还是反转链表的尾节点?
? ? ? ? 1.如果递归函数返回的指针指向反转链表头节点,那么每次递归后,都要从反转链表的头节点开始遍历,遍历到反转链表尾部,然后挂上新的尾节点head,但是这样的话,每一次递归都要遍历,时间复杂度是显而易见的O(n^2),题目的范围又是5000,显然会超时。
? ? ? ? 2.如果递归函数返回的指针指向反转链表尾节点,那么把新的尾节点head挂到反转链表尾部就很容易,只需要直接链接即可。整个递归程序,时间复杂度为O(n)。看似很完美,但是也有个问题,整个反转链表构建完毕后,返回的是整个反转链表的尾节点,与题目要求不符。
? ? ? ? 我采用的是第二种方法,加了一些小小的改变,当递归程序查找到原链表最后一个节点时(即反转链表的头节点),使用一个全局变量记录下该节点,之后继续进行递归程序,直到反转链表构建完毕。最后返回该全局变量即可。
代码如下:
/**
* 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:
// reversehead用来记录反转链表的头节点
ListNode *reversehead=NULL;
ListNode* reverseList(ListNode* head) {
f(head);
return reversehead;
}
// 函数f的功能,将当前头节点head,连接到反转后链表的最后一个位置 并返回反转链表的最后一个节点
ListNode *f(ListNode* head)
{
if(head==NULL) return NULL;
// 将head->next之后的链表反转,并返回最后一个节点
ListNode *tail=f(head->next);
// 如果head->next之后的链表反转后最后一个节点为空,说明head->next本身为NULL
// 则head为原链表最后一个节点,也是反转链表的头节点
if(tail==NULL)
{
// 记录下反转后链表的头节点
reversehead=head;
// 返回该节点
return head;
}
// 反转链表尾部追加head节点,head节点成为反转链表最后一个节点
tail->next=head;
// 断开head和原链表的链接
head->next=NULL;
// 返回反转后链表的最后一个节点
return head;
}
};
|