给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
实现代码:
双指针迭代法
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
ListNode* pre=NULL;
ListNode* cur=head;
while(cur)
{
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
};
其实就相当于不断的用头插法而已,不过要注意记录每次新的头节点,while循环中的temp用来记录cur后面的链表,因为要改变cur->next,然后重新让cur=temp,进入下一次循环。
-
时间复杂度:O(n)
-
空间复杂度:O(1)
从前往后翻转的双指针递归法
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur)
{
if(cur==NULL)
{
return pre;
}
ListNode* temp=cur->next;
cur->next=pre;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head)
{
return reverse(NULL,head);
}
};
这个和双指针法思想一样的,只不过用递归来写,里面的reverse其实就是相当于双指针法里的pre=cur,cur=temp而已,递归每进入一层,就相当于双指针法里while循环一次,所以在递归函数里有一个if(cur==NULL)的递归终止条件和while里的终止条件是一致的,理解了双指针法,这个方法就很容易理解了。
从后往前翻转的递归法
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
if(!head||!head->next)
{
return head;
}
ListNode* newhead=reverseList(head->next);
head->next->next=head;
head->next=NULL;
return newhead;
}
};
这个方法是从后往前翻转的,会比上面两种方法难理解一些,可以自己画一个链表,然后跟着代码模拟走一遍,就容易明白一些了。
-
时间复杂度:O(n)
-
空间复杂度:O(n),递归调用的栈空间