解法一 迭代
最直接的想法,利用链表特性
使用beg,mid,end三个指针,在向后访问过程中将原链表中指针逆向
例如
1
→
2
1\rightarrow2
1→2 转为
1
←
2
1\leftarrow2
1←2
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr)
return head;
else if(head->next == nullptr)
return head; //只有一个或无节点直接返回
ListNode *beg = head,*mid = beg->next,*end = nullptr;
head->next = nullptr; //原头指针倒置后应当指向null
while(mid){
end = mid->next; //逆向前保存“高位”信息
mid->next = beg; //逆向
beg = mid; //迭代向前
mid = end;
}
return beg;
}
};
踩的坑
- 未利用链式存储特性,只想采用顺序表插入方式
- 未设置原头指针next为null,导致力扣出现执行出错情况(这也很好理解,head->next==null 为链表顺序遍历至末尾标志)
执行出错:堆在释放后使用(heap-use-after-free),一般和随意释放内存有关。
但是我并没有动态分配内存
未设置原头指针next为null,第一个元素仍然指向第二个元素,因而导致第一二个元素间形成了一个环,可能会倒置判题内部程序出现这样的问题吧?
执行出错报错大概就像这样:
另一实现
将beg,mid,end向前提,在一开始就完成设置原头指针next为null
不需在循环外设置head->next = nullptr
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr)
return head;
else if(head->next == nullptr)
return head;
ListNode *beg = nullptr,*mid = head,*high = nullptr;
while(mid){
high = mid->next;
mid->next = beg;
beg = mid;
mid = high;
}
return beg;
}
};
解法二 重新插入
类似尾插法
断开头指针,依次重新插入,将head当作尾指针依次向后移
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr)
return head;
else if(head->next == nullptr)
return head;
ListNode* p = head;
head = nullptr; //断开头结点
while(p){
ListNode* NextNode = p->next; //后续更改p,提前保存下一个结点信息
p->next = head;
head = p;
p = NextNode;
}
return head;
}
};
踩的坑
- 链表无头结点,头指针直接指向首元结点(头结点显然不是必须的,本题就没有)
- 变量更新的顺序,例如在p改变前保存NextNode
头插法
在新链表中增加头结点(原链表无头结点),在头结点和首元结点之间不断插入(后插入的元素离头结点近),完成倒序
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr)
return head;
else if(head->next == nullptr)
return head;
ListNode* p = new ListNode; //p作为新链表头结点
p->next = nullptr; //初始时头结点指向null
while(head){ //head向后遍历原链表
ListNode* NextNode = head->next;
head->next = p->next; //头插法
p->next = head;
head = NextNode;
}
return p->next;
}
};
踩的坑
- 新链表头结点p需要动态分配内存,不然会报错:member access within address 0x602000000058 with insufficient space for an object of type ‘ListNode’ (solution.cpp) 即结点p空间不足
解法三 递归
想不到
递归访问至尾结点,并将其设为p(倒置后头结点)后向上返回
先看最简单的倒数第二个结点情况:
作为函数参数传入的不是头指针,就是倒数第二个结点。通过head->next->next = head完成倒置,并设next为null(很关键,通过递归不断设置为最后一个节点)
再向上返回函数至倒数第三个结点。注意:原链表结构并未完全改变,倒数第三个节点仍然指向倒二结点,因此可以重复上述倒置过程
递归调用,完成倒置
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr)
return head;
else if(head->next == nullptr)
return head;
ListNode *p = reverseList(head->next); //previous tail node
head->next->next = head;
head->next = nullptr;
return p;
}
};
踩的坑
- 头尾结点倒置后已经互换,应该直接返回p,而不是head