重排链表
题目描述
Category | Difficulty | Likes | Dislikes |
---|---|---|---|
algorithms | Medium (65.94%) | 1513 | - |
-
Tags
-
Companies
Unknown
给定一个单链表 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. 链表的中间结点」)。
我们可以使用快慢指针来 O(N) 地找到链表的中间节点。
将原链表的右半端反转(参考「206. 反转链表」)。
我们可以使用迭代法实现链表的反转。
将原链表的两端合并。
因为两链表长度相差不超过 1,因此直接合并即可。
代码
class Solution
{
public:
ListNode *reorderList(ListNode *head)
{
if (head->next == nullptr)
return head;
ListNode *dummy = new ListNode(0, head);
ListNode *fast = dummy, *slow = dummy;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
ListNode *reverseHalfHead = reverseList(slow->next);
slow->next = nullptr;
ListNode *preHalfHead = head;
while (preHalfHead && reverseHalfHead)
{
ListNode *tmp = reverseHalfHead->next;
reverseHalfHead->next = preHalfHead->next;
preHalfHead->next = reverseHalfHead;
preHalfHead = preHalfHead->next->next;
reverseHalfHead = tmp;
}
return dummy->next;
}
ListNode *reverseList(ListNode *head)
{
ListNode *cur = head->next;
head->next = nullptr;
ListNode *tmp = cur;
while (cur)
{
tmp = cur->next;
cur->next = head;
head = cur;
cur = tmp;
}
return head;
}
};
复杂度分析
- 时间复杂度:O(N),其中 N 是链表中的节点数。
- 空间复杂度:O(1)。