给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。Leetcode:206. 反转链表
示例 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指针所指向应该是2的地址,由于反转链表,1指针所指向的应该是空指针,这里我们设置了三个指针,N1,N2,N3,N1指针初始化为空指针,N2指针为头指针,N3指针为头指针指向的下一个指针。我们将N1初始化为空指针,方便第一个元素指向为空指针,当我们利用 N2->next = N1此时指针所指向的对象就反转了,此时N2不再指向N3,然后我们将N1 = N2,N2 = N3,N3 = N3 -> next 目的是下一个箭头翻转,N3的作用是跳到下一个需要翻转的位置,不断循环往复.直到N3指向空指针, N2,N1完成最终的交换,思路如下:
注意如果,我们的链表为空,或者只有一个元素则不需要翻转!
代码实现如下:
SListNode* reverseList(SListNode* Pphead){
// assert(Pphead);
if(Pphead == NULL || Pphead->next == NULL){
return Pphead;
}
SListNode* Node1 = NULL;
SListNode* Node2 = Pphead;
SListNode* Node3 = Node2->next;
while (Node2)
{
Node2->next = Node1;
Node1 = Node2;
Node2 = Node3;
if(Node3){
Node3 = Node3->next;
}
}
return Node1;
}
关于递归思想解决,类似于汉诺塔,和青蛙跳台阶的思想,
“将一个规模为 n 的问题,转化为一个或多个规模更小(如 n-1)的子问题,并且这些子问题的结构和原问题相同。”
算法实现:
SListNode* reverseList(SListNode* Pphead){
if(Pphead ==NULL || Pphead->next == NULL){
return Pphead;
}
SListNode* New_head = reverseList(Pphead->next);
Pphead->next->next = Pphead;
Pphead->next = NULL;
return New_head;
}
利用“头插法“,创建一个新的链表结构,将之前的链表的每一个节点插入即可,然后返回新链表的头指针。
算法实现:头插法的思路和迭代法的基本一致,只是头插法,新增了一个链表结构而已。
SListNode* reverseList(SListNode* Pphead){
// assert(Pphead);
if(Pphead == NULL || Pphead->next == NULL){
return Pphead;
}
SListNode* Cur = Pphead;
SListNode* New_head = NULL;
SListNode* NEXT = Pphead->next;
while (Cur)
{
Cur->next = New_head;
New_head = Cur;
Cur = NEXT;
if(NEXT){
NEXT = NEXT->next;
}
}
return New_head;
}
好了本期就到这里,这里翻转链表的方法非常值得我们学习,我们知道改变链表指针的指向需要至少三个指针进行遍历!同时递归将规模大转化为规模小的问题思想在实际应用可能会非常灵活!