方法一:迭代
思路
假设链表为 1 → 2 → 3 → ∅ 1\rightarrow 2 \rightarrow 3 \rightarrow \emptyset 1→2→3→∅,我们需要返回 ∅ ← 1 ← 2 ← 3 \emptyset \leftarrow 1 \leftarrow 2 \leftarrow 3 ∅←1←2←3 。
链表的问题往往可以使用双指针来解决,我们可以一次遍历链表来完成这个操作,初始化pre指向 ∅ \emptyset ∅,cur指向1,遍历链表的循环条件为cur非空,结果返回为pre。
我们再来看循环中如何执行,我们将当前节点cur的next指向pre,由于循环中需要根据cur的next继续执行,所以需要额外存储cur的next结点。
Code
/**
* 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) {
ListNode* pre = nullptr, *cur = head;
while(cur){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n),其中n为链表长度。 -
空间复杂度:
O ( 1 ) O(1) O(1),其中n为链表长度。
方法二:递归
思路
假设链表为 1 → 2 → 3 → ∅ 1 \rightarrow 2 \rightarrow 3 \rightarrow \emptyset 1→2→3→∅,我们需要返回 ∅ ← 1 ← 2 ← 3 \emptyset \leftarrow 1 \leftarrow 2 \leftarrow 3 ∅←1←2←3 。
链表的问题另一种解法往往可以使用递归来解决,递归问题的思考可以拆分成两个部分去思考,即递和归。
- 递:将原问题拆分成子问题,子问题与原问题是相似的且规模比原问题小,不断拆分后会有一个尽头,即递归边界条件。
- 原问题:将整个链表反转。
- 子问题:将当前节点的下一个节点的next指向自己。
- 递归边界条件:当节点到尾节点时终止,在例中为3。
- 归:问题的最终返回,在本例中为3。
- 特殊情况:
- 考虑链表为 ∅ \emptyset ∅ 时无需递归直接返回。
- 当链表为 1 → 2 → ∅ 1 \rightarrow 2 \rightarrow \emptyset 1→2→∅时,根据上述递归执行会形成环,此时链表为 1 ↔ 2 1 \leftrightarrow 2 1↔2,故子问题还需增加 1 → ∅ 1 \rightarrow \emptyset 1→∅。
Code
/**
* 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 == nullptr || head->next == nullptr){
return head;
}
ListNode* res = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return res;
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n),其中n为链表长度。 -
空间复杂度:
O ( n ) O(n) O(n),其中n为链表长度。