题目
反转一个单链表。
示例
输入:
1->2->3->4->5->NULL
输出:
5->4->3->2->1->NULL
解法探析
解法 1:迭代法
思路分析
在遍历链表时,将当前结点的 next 指针改为指向其前一个结点。由于结点不会指向前一个结点,因此必须先存储其前一个结点。在更改指向之前,还需要另外一个指针来存储后一个结点。最后,返回新的头指针。
代码实现
C实现:
struct ListNode {
int val;
struct ListNode* next;
};
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* node = head; // 当前指针,指向当前遍历到的结点
struct ListNode* prev = NULL; // 前驱指针,指向当前结点的前一个结点
struct ListNode* reverseHead = NULL; // 新的头指针,指向反转后链表的头结点,即原始链表的尾结点
// 若当前指针不为 NULL
while (node != NULL) {
struct ListNode* pNext = node->next; // 后继指针,指向当前结点的后一个结点
if (pNext == NULL) { // 若后继指针为 NULL,则已到链表的末尾,新的头指针等于当前指针
reverseHead = node;
}
node->next = prev; // 当前结点的 next 指针指向前驱结点
prev = node; // 更新前驱指针
node = pNext; // 当前指针后移
}
return reverseHead;
}
C++实现:
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* node = head;
ListNode* prev = nullptr;
ListNode* reverseHead = nullptr;
while (node != nullptr) {
ListNode* pNext = node->next;
if (pNext == nullptr) {
reverseHead = node;
}
node->next = prev;
prev = node;
node = pNext;
}
return reverseHead;
}
};
GO实现:
type ListNode struct {
Val int
Next *ListNode
}
func reverseList(head *ListNode) *ListNode {
node := head
var prev *ListNode = nil
var reverseHead *ListNode = nil
for node != nil {
pNext := node.Next
if pNext == nil {
reverseHead = node
}
node.Next = prev
prev = node
node = pNext
}
return reverseHead
}
复杂度分析
时间复杂度:(O(n))(假设 n 为链表的长度)
空间复杂度:(O(1))
动态图解
解法 2:递归法
思路分析
递归法稍微复杂了一些,其关键在于反向工作。假设链表是 1->2->3->4->5->NULL,则递归过程如下:
1.底层最后一个 reverseList(5) 返回了 5 这个结点。
2.在 reverseList(4) 中,reverseHead 为 5,head 为4,head->next->next = head 相当于 5->4。
3.此时结点的情况为 4->5->4,为了防止链表循环,使用 head->next = null 切断 4->5 这一条,最后返回:5->4->NULL。
4.返回到上一层 reverseList(3),最后返回:5->4->3->NULL。
5.reverseList(2)、reverseList(1) 依次类推,最后返回:5->4->3->2->1->NULL。
代码实现
C实现:
// 定义单链表的结点类型
struct ListNode {
int val;
struct ListNode* next;
};
struct ListNode* reverseList(struct ListNode* head)
{
// 若当前结点为 NULL,或者下一个结点为 NULL,则递归终止
if (head == NULL || head->next == NULL) {
return head;
}
// 结点 reverseHead 就是反转链表的头结点
struct ListNode* reverseHead = reverseList(head->next);
// 将反转链表的尾结点(head->next)的 next 指向当前即将反转的结点
// 如果链表是 1->2->3->4->5,那么此时的 reverseHead 就是5,
// 而 head 是4,head 的下一个是5,下下一个是空,所以 head->next->next 就是5->4
head->next->next = head;
// 防止链表循环,将head->next置为 NULL
head->next = NULL;
// 每层递归函数都返回reverseHead,也就是最后一个结点
return reverseHead;
}
C++实现:
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return head;
}
ListNode* reverseHead = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return reverseHead;
}
};
GO实现:
type ListNode struct {
Val int
Next *ListNode
}
func reverseList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
reverseHead := reverseList(head.Next)
head.Next.Next = head
head.Next = nil
return reverseHead
}
复杂度分析
时间复杂度:(O(n))(假设 n 为链表的长度)
空间复杂度:(O(n))(由于使用递归,会使用隐式栈空间,递归深度可能会达到 n 层)
个人主页: