143. 重排链表
题目描述
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例 2:
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
提示:
链表的长度范围为 [1, 5 * 104]
1 <= node.val <= 1000
解题思路
思路:思路很简单,主要分为三步,第一步是使用双指针找到链表中点位置(注意如果有两个中点则返回第二个节点即后半段起始位置),第二步是使用三指针将链表后半段反转,第三步是将前后这两段链表进行合并即将后半段链表插入前半段链表中。很多细节需要注意!
// 876.链表的中间节点
class Solution {
public:
ListNode* middleNode(ListNode* head) {
// 快慢指针
ListNode* L=new ListNode();
L->next=head;
ListNode* fast=L;
ListNode* slow=L;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
// 当fast还有时要返回的是slow的下一个即第二个节点
if(fast)
return slow->next;
return slow;
}
};
// 206.反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// 1个及以下不用反转
if(head==nullptr||head->next==nullptr)
return head;
// 当前节点
ListNode* p=head;
// 当前节点下一个节点
ListNode* q=p->next;
// 用于翻转的尾部
ListNode* r=nullptr;
while(p&&q)
{
p->next=r;
r=p;
p=q;
q=q->next;
}
//最后出来肯定是q为空
p->next=r;
return p;
}
};
// 143.重排链表
class Solution {
public:
void reorderList(ListNode* head) {
// 1.找到链表中点 slow是后半段第一个
ListNode* L=new ListNode();
L->next=head;
ListNode* fast=L;
ListNode* slow=L;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
if(fast)
slow=slow->next;
// 2.后半段反转 p是第二段第一个节点
ListNode* p=slow;
ListNode* q=p->next;
ListNode* r=nullptr;
while(p&&q)
{
p->next=r;
r=p;
p=q;
q=q->next;
}
//最后一步 q为空 处理p
p->next=r;
// 3.合并两段 将第二段插入第一段
ListNode* h1=head;
ListNode* h2=p;
ListNode* h3=h2->next;
while(h2&&h3)
{
h2->next=h1->next;
h1->next=h2;
h1=h1->next->next;
h2=h3;
h3=h3->next;
}
// 最后h3肯定为空 为h2的next置空
h2->next=nullptr;
}
};