Huge Lemon的博客

重排链表

2020-02-29

LeetCode 143. Reorder List

题目描述


给定一个单链表 $L:L_0→L_1→…→Ln-1→L_n$ ,
将其重新排列后变为: $L_0→L_n→L_1→Ln-1→L_2→Ln-2→…$

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

给定链表 1->2->3->4, 重新排列为 1->4->2->3.

示例 2:

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.


解题思路

给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

通过观察,可以将重排链表分解为以下三个步骤:

  1. 首先重新排列后,链表的中心节点会变为最后一个节点。所以需要先找到链表的中心节点:876. 链表的中间结点
  2. 可以按照中心节点将原始链表划分为左右两个链表。
    1. 按照中心节点将原始链表划分为左右两个链表,左链表:1->2->3 右链表:4->5
    2. 将右链表反转,就正好是重排链表交换的顺序,右链表反转:5->4。反转链表:206. 反转链表
  3. 合并两个链表,将右链表插入到左链表,即可重新排列成:1->5->2->4->3.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/

// 1. 使用快慢指针,找出链表的中心节点
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast = head, *slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}

// 2. 通过递归反转链表
struct ListNode* reverseList(struct ListNode* head){
if(!head || !head->next)
return head;
struct ListNode *L = malloc(sizeof(struct ListNode)), *p;
L->next = NULL;
while(head != NULL) {
p = head->next;
head->next = L->next;
L->next = head;
head = p;
}
return L->next;
}

// 3. 合并两个链表,将右链表插入到左链表
void mergeList(struct ListNode* left, struct ListNode* right){
struct ListNode *leftTemp, *rightTemp;

// merge的循环时候条件应为: 当右链表为空的时候,就结束循环
// 原因是:
// 1.你取了中心节点的next为右链表的head, 那么两者的长度一定是 左链表 > 右链表
// 2. 当原始链表为: 奇数 左链表=右链表+1 ; 偶数 左链表=右链表+2
// 所以: 只用判断右链表的节点是否为空就可以了,而不用判断左链表. 左链表的next肯定有值.
while(right != NULL){
//1. 保存next节点
leftTemp = left->next;
rightTemp = right->next;

// 2. 将右链表的第一个节点插入到左链表中
// 左链表:1->2->3 右链表:5->4
// 合并后的左链表:1->5->2->3
left->next = right;
right->next = leftTemp;

// 3. 移动left和right指针
// 左链表变为:2->3 右链表变为:4
left = leftTemp;
right = rightTemp;
}
}


void reorderList(struct ListNode* head){
if(!head || !head->next)
return head;

// 1. 使用快慢指针,找出链表的中心节点。
// 1->2->3->4->5,中心节点为3
struct ListNode *middle = middleNode(head);

// 2. 将原始链表按照中心链表分割为两个链表,并将右链表反转
// 2.1 原始链表:1->2->3->4->5 左链表:1->2->3 右链表:4->5
struct ListNode *left = head, *right = middle->next;
middle->next = NULL;

// 2.2 反转右链表
//原始右链表:4->5 反转后:5->4
right = reverseList(right);

// 3. 合并两个链表,将右链表插入到左链表
// 左链表:1->2->3 右链表:4->5 合并后:1->5->2->4->3
mergeList(left, right);
}
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏