题目描述
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
思路描述
方法一 双指针
采用两个指针一前一后,前面的指针用于遍历下一结点,后面的指针用于保存新链表的头节点位置,合理利用现有指针head暂存下一节点位置,然后将新结点指向新链表头结点完成链接,更新头结点和下一结点的指针。依次遍历直到末尾,在插入最后一个节点前head正好指向空结点,插入完成后前面的指针也指向空,跳出循环,返回翻转后的链表。
代码
/**
* 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* p=head->next;
ListNode* q=head; //新链表头节点
while(p){
head->next=p->next; //暂时保存新节点的下一节点
p->next=q; //新节点指向新链表头节点
q=p; //头节点更新
p=head->next; //更新移动指针,继续遍历
}
return q;
}
};
方法二 栈思想
栈的特点就是后进先出么,利用这一特点先将所有结点入栈,再逐个出栈,链接成新链表即为翻转后的链表。注意在入栈结束后判空操作,减少浪费时间空间。
代码
/**
* 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) {
std::stack<ListNode*> st; //定义栈,ListNode类型
//将所有元素入栈
while (head) {
st.push(head);
head = head->next;
}
//栈为空说明原链表为空,直接返回
if (st.empty()) {
return nullptr;
}
ListNode* L = st.top();//获取栈顶元素
st.pop();//出栈
ListNode* p = L; //移动指针
while (!st.empty()) {
//暂存新节点
ListNode* temp = st.top();
st.pop();//出栈
p->next = temp;//链接新节点
p = p->next;//指针后移
}
p->next = nullptr;//最后一个节点的下一指针设为空
return L;
}
};
方法三 递归
递归要找到递归中止条件,在本题中就是空链表或者只有一个元素则返回。下一步递归调用就是从当前结点的下一结点开始递归,再下一步逻辑处理,将当前结点挂到递归返回的结点的末尾,最终返回反转后的链表。
代码
/**
* 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* n = head->next;
//递归得到翻转后的链表,翻转后n为链表reverse的尾节点
ListNode* reverse =reverseList(n);
//把当前节点head,挂在尾节点n的后面
n->next=head;
//head成为新的尾节点,后面设为空
head->next=nullptr;
return reverse;
}
};