给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
解法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* newList=new ListNode();//初始化新链表
ListNode* cur=head;
while(cur!=nullptr)
{
ListNode* newnode=new ListNode(cur->val);
newnode->next=newList->next;
newList->next=newnode;
cur=cur->next;
}
return newList->next;//多出一个初始化的0节点,next去除它
}
};
定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。
解法2(双指针法)
其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,并没有添加或者删除节点,仅仅是改变next指针的方向
如图所示:
之前链表的头节点是元素1, 反转之后头结点就是元素5 ,这里并没有添加或者删除节点,仅仅是改变next指针的方向。
那么接下来看一看是如何反转的呢?
我们拿有示例中的链表来举例,如动画所示:(纠正:动画应该是先移动pre,在移动cur)
。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==nullptr || head->next==nullptr)
{
return head;
}
ListNode* cur=head;
ListNode* pre=nullptr;//反转后头节点指向空
while(cur!= nullptr){
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
};
解法3(递归法)
递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。
class Solution {
public:
ListNode* dfs_reverseList(ListNode* pre,ListNode* cur)
{
if(cur==nullptr )
{
return pre;
}
ListNode* temp=cur->next;
cur->next=pre;
return dfs_reverseList(cur,temp);
}
ListNode* reverseList(ListNode* head) {
return dfs_reverseList(nullptr,head);
}
};