开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
LeetCode 143. Reorder List
给定一个单链表 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
算法
(链表,模拟) O(n) 假设初始的链表是 L1→L2→L3→…→LnL1→L2→L3→…→Ln。
分两步处理:
1.将后半段的指针都反向,变成:L1→L2→L3→…→L⌈n/2⌉←L⌈n/2⌉+1←…←LnL1→L2→L3→…→L⌈n/2⌉←L⌈n/2⌉+1←…←Ln;
2.用两个指针分别从1和n开始往中间扫描,将后半段交替插入到前半段,变成:L1→Ln→L2→Ln−1→…;\
时间复杂度分析:整个链表总共扫描三次,第一次求总长度,第二次将后半段反向,第三次将后半段交替插入前半段,所以总时间复杂度是 O(n)。
先把链表的后半部分反转过来,然后就可以从两端开始遍历,将末尾节点插入第kk个节点后面。时间复杂度:查找中间节点O(n),反转后半部分链表O(n),依次插入后半部分的节点O(n),总的时间复杂度为O(n)。
C++ 代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
int n = 0;
for (ListNode *p = head; p; p = p->next) n ++ ;
if (n <= 2) return;
ListNode *later = head;
for (int i = 0; i + 1 < (n + 1) / 2; i ++ )
later = later->next;
ListNode *a = later, *b = later->next;
while (b){
ListNode *c = b->next;
b->next = a;
a = b;
b = c;
}
later->next = 0;
while (head && head != a){
b = a->next;
a->next = head->next;
head->next = a;
head = head->next->next;
a = b;
}
}
};
(暴力枚举) O(n2)
题解1:暴力解法,每次找到链表末尾节点插入到原来第kk个节点后面。时间复杂度O(n2)O(n2) C++ 代码
void reorderList(ListNode* head) {
if(!head || !head->next || !head->next->next)return ;
ListNode* dummy = new ListNode(0);
dummy->next = head;
//head是第k个节点的位置
while(head->next && head->next->next)
{
ListNode* tail = head;
//找到末尾节点的前驱节点,同时将末尾节点插入到head后面
while(tail->next->next) tail = tail->next;
tail->next->next = head->next;
head->next = tail->next;
//更新tail和head
tail->next = NULL;
head = head->next->next;
}
}