一、题目描述
反转一个单链表。一道非常简单,非常基础的题,然而我某次面试竟然没写出来......所以在这里好好反思总结一下。
二、迭代法
以“1->2->3->4->5->nullptr”为例。
如果链表没有节点或者只有1个节点,那么直接返回即可,不需要做操作,所以最小规模的情况要2个节点。
从第2个节点开始迭代,每一次要将当前节点指向上一个head,并且要将head每次都更新为指向当前节点。除此之外还要注意,最开始的head指向的节点一定是尾节点,所以要把开始的head的next域置为nullptr,代码如下:
/**
* 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 || !head->next) return head;
ListNode *p = head->next;
head->next = nullptr; //第一个节点是反转后的最后一个节点,next域置为nullptr
//每次迭代,将当前节点指向上一个head,并将head更新为当前节点
while(p)
{
ListNode *temp = p->next;
p->next = head;
head = p;
p = temp;
}
return head;
}
};
三、递归法
迭代法的思想熟悉以后,递归法就很简单了。开始也是,0个或1个节点不需要做处理;reverseList(head->next)返回了后面这个子链表反转后的头,这个头其实就是整个链表反转以后的头,我们现在要做的就是将后面反转后的子链表的尾连到初始链表的第一个节点上,那么后面子链表反转后的尾是什么呢?其实就是开始的head->next。这样整个问题就解决了,代码如下:
/**
* 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 || !head->next) return head;
//将后面子链表反转后的尾保存一下,其实不存也可以,只是这样的逻辑更清楚
ListNode *tail = head->next;
//后面子链表反转后的头就是整个链表反转后的头
ListNode *newhead = reverseList(head->next);
//将后面子链表的尾连到第一个节点上
tail->next = head;
head->next = nullptr;
return newhead;
}
};