题目描述
翻转一个单链表。
进一步: 能否同时给出迭代算法和递归算法?
样例
输入:1->2->3->4->5->NULL
输出:5->4->3->2->1->NULL
算法1
(链表操作,迭代) $O(n)$
翻转即将所有节点的next指针指向前驱节点。
由于是单链表,我们在迭代时不能直接找到前驱节点,所以我们需要一个额外的指针保存前驱节点。同时在改变当前节点的next指针前,不要忘记保存它的后继节点。
空间复杂度分析:遍历时只有3个额外变量,所以额外的空间复杂度是 $O(1)$。
时间复杂度分析:只遍历一次链表,时间复杂度是 $O(n)$。
C++ 代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *prev = nullptr;
ListNode *cur = head;
while (cur)
{
ListNode *next = cur->next;
cur->next = prev;
prev = cur, cur = next;
}
return prev;
}
};
算法2
(链表操作,递归) $O(n)$
首先我们先考虑 reverseList
函数能做什么,它可以翻转一个链表,并返回新链表的头节点,也就是原链表的尾节点。
所以我们可以先递归处理 reverseList(head->next)
,这样我们可以将以head->next
为头节点的链表翻转,并得到原链表的尾节点tail
,此时head->next
是新链表的尾节点,我们令它的next指针指向head
,并将head->next
指向空即可将整个链表翻转,且新链表的头节点是tail
。
空间复杂度分析:总共递归 $n$ 层,系统栈的空间复杂度是 $O(n)$,所以总共需要额外 $O(n)$ 的空间。
时间复杂度分析:链表中每个节点只被遍历一次,所以时间复杂度是 $O(n)$。
C++ 代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *tail = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return tail;
}
};
可不可以使用栈呢?
可以的。
请问可以把递归题解转到我的CSDN上的博客里吗?
可以,注明出处即可。
递归解法,学习到了!感谢
灿哥我对这个递归解法还是不太明白,感觉不太好理解呀
简单来说,每次递归会先把后 $n - 1$ 个节点翻转,然后把当前的头结点接在后 $n - 1$ 个节点的后面。
在纸上画画图可能会比较好理解。