反转链表
一、题源:
206. 反转链表
问题描述
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
二、 思路:
1、头插法
将这个链表上的结点依次头插到一个新的链表。为了简化头插代码,在新的链表上引入了虚拟头结点
参考代码如下
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* returnHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* ptr;
returnHead->next = 0;
while(head)
{
ptr = head;
head = ptr->next;
ptr->next = returnHead->next;
returnHead->next = ptr;
}
ptr = returnHead;
returnHead = ptr->next;
free(ptr);
return returnHead;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
2、递归法(一)
这个递归法是我自己的思路,反转以head为头结点的单链表的问题分解为反转以head->next为头结点的单链表和将head结点插到末尾;
参考代码如下
struct ListNode* reverseList(struct ListNode* head){
if(head && head->next)
{
struct ListNode* ptr, *returnHead;
//1、反转以head->next为头结点的单链表
returnHead = reverseList(head->next)
//2、将head结点插到末尾
ptr = head->next;
head->next = ptr->next;
ptr->next = head->next;
return returnHead;
}
return head;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
3、双指针法
这里的双指针法和后面的**递归法(二)**是我参考 反转链表 这篇文章写的,具体的大家可以看这篇文章的解释,写的很清楚,这里就不再解释了。
参考代码如下
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* pre = 0;
struct ListNode* ptr;
while(head)
{
ptr = head;
head = ptr->next;
ptr->next = pre;
pre = ptr;
}
return pre;
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
4、递归法(二)
实际上和之前的双指针法中迭代的过程一样,只是通过递归来实现了。
参考代码如下
struct ListNode* reverse(struct ListNode* pre,struct ListNode* cur){
if(cur == NULL) return pre;
struct ListNode* nextCur = cur->next;
cur->next = pre;
return reverse(cur,nextCur);
}
struct ListNode* reverseList(struct ListNode* head) {
return reverse(NULL, head);
}
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
三、总结
四种方法的话时间复杂度差距不大,但是空间复杂度的话,递归法需要额外的栈空间,所以空间复杂度比非递归的要高。