解题思路
1.题目描述
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例2:
输入:head = [1,2]
输出:[2,1]
示例3:
输入:head = []
输出:[]
来源:力扣(LeetCode)
2.题目分析
2.1 牺牲空间重构链表
这道题就是个十分简单的节点方向操作题,不涉及什么复杂的算法。我们可以通过构造一个带有头结点的链表使用头插法来实现一个新的反向链表。以[1,2,3]为例演示如下
2.1 原地迭代修改
原地迭代修改就是在每次遍历链表时,让当前cur
节点的next
指针指向前一个节点(完成局部倒置)。不过这种局部修改会使得链表断开,所以我们必须在修改当前节点前将其next节点提前保存。在更改引用之前,还需要存储后一个节点。在完成一次迭代倒置之后分别向前移动cur
指针和pre
指针的位置,最后返回新的头指针pre
。其核心代码如下所示
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
2.2 递归解决
2.2.1 为什么可以使用递归
我们首先需要明白链表与递归有着天然的亲和性;接下来我们来看反转链表的问题,对于链表来说我们可以将其拆分为两个部分(头节点head
和其他部分),此时的头节点head不需要反转,我们只需要将头节点之后的链表的倒置链表尾部加上头节点head
就完成了总体的倒置。对于头节点之后的局部链表可以进行类似的拆分工作,这样就形成了递归的解法。
2.2.2 递归解决
递归的思想在于将问题逐步分解。递归通常与栈相关联,这是因为递归本身就是一个逆向的操作,鉴于此我们可以借助递归的逆向操作将链表进行倒置。假设有链表 [1–>2–>3–>4] ,若以经完成部分转向,假设现在处于 [1-->2-->3<--4]
的状态,那么我们此时要处理的就是节点2和3
之间的关系,此时我们就需要让3的next
指向2,2的next
指向3的next
。
我们将具体的递归过程分为以下两个过程:递以及归。
- 其中的递就是一步一步将问题分解,也就是要处理
1
就要先处理2
,要处理2
就要先处理3
,以此类推,总之就是要先处理最后一个节点4
。 - 递完之后我们要归的话此时的顺序是逆的,此时我们可以趁机进行链表的局部反转。如在处理4结点的时候我们注意到其
next
为空也就是它是最后一个节点,那么4将会是新的首节点,此时我们回过头处理3,此时基于3将两个节点3和4进行倒置,以此类推逐步进行指针节点指向的节点和其下一个节点的倒置。 - 需要注意的是递归都是需要确定递归终止条件的,在本题中因为在拆解链表到只要一个节点时间就可以不用倒置,所以我们选择边界条件为
head == NULL || head->next == NULL)
3.题目解答
3.1 头插法重构链表解决
/**
* 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* cur = head;
ListNode* pre = new ListNode();
ListNode* temp;
while(cur!=nullptr){
temp = cur->next;
cur->next = pre->next;
pre->next = cur;
cur = temp;
}
cur = pre->next;
delete(pre);
return cur;
}
};
3.2 原地迭代反转
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
curr->next = prev;
prev = curr;
curr = next;
}
return prev;
}
};
3.3 递归解法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == NULL || head->next == NULL){
return head;
}
ListNode* nex = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return nex;
}
};