0143-重排链表

Raphael Liu Lv10

给定一个单链表 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

方法一:线性表

因为链表不支持下标访问,所以我们无法随机访问链表中任意位置的元素。

因此比较容易想到的一个方法是,我们利用线性表存储该链表,然后利用线性表可以下标访问的特点,直接按顺序访问指定元素,重建该链表即可。

代码

[sol1-C++]
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
class Solution {
public:
void reorderList(ListNode *head) {
if (head == nullptr) {
return;
}
vector<ListNode *> vec;
ListNode *node = head;
while (node != nullptr) {
vec.emplace_back(node);
node = node->next;
}
int i = 0, j = vec.size() - 1;
while (i < j) {
vec[i]->next = vec[j];
i++;
if (i == j) {
break;
}
vec[j]->next = vec[i];
j--;
}
vec[i]->next = nullptr;
}
};
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public void reorderList(ListNode head) {
if (head == null) {
return;
}
List<ListNode> list = new ArrayList<ListNode>();
ListNode node = head;
while (node != null) {
list.add(node);
node = node.next;
}
int i = 0, j = list.size() - 1;
while (i < j) {
list.get(i).next = list.get(j);
i++;
if (i == j) {
break;
}
list.get(j).next = list.get(i);
j--;
}
list.get(i).next = null;
}
}
[sol1-Golang]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func reorderList(head *ListNode) {
if head == nil {
return
}
nodes := []*ListNode{}
for node := head; node != nil; node = node.Next {
nodes = append(nodes, node)
}
i, j := 0, len(nodes)-1
for i < j {
nodes[i].Next = nodes[j]
i++
if i == j {
break
}
nodes[j].Next = nodes[i]
j--
}
nodes[i].Next = nil
}
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void reorderList(struct ListNode* head) {
if (head == NULL) {
return;
}
struct ListNode* vec[40001];
struct ListNode* node = head;
int n = 0;
while (node != NULL) {
vec[n++] = node;
node = node->next;
}
int i = 0, j = n - 1;
while (i < j) {
vec[i]->next = vec[j];
i++;
if (i == j) {
break;
}
vec[j]->next = vec[i];
j--;
}
vec[i]->next = NULL;
}
[sol1-Python3]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def reorderList(self, head: ListNode) -> None:
if not head:
return

vec = list()
node = head
while node:
vec.append(node)
node = node.next

i, j = 0, len(vec) - 1
while i < j:
vec[i].next = vec[j]
i += 1
if i == j:
break
vec[j].next = vec[i]
j -= 1

vec[i].next = None

复杂度分析

  • 时间复杂度:$O(N)$,其中 $N$ 是链表中的节点数。

  • 空间复杂度:$O(N)$,其中 $N$ 是链表中的节点数。主要为线性表的开销。

方法二:寻找链表中点 + 链表逆序 + 合并链表

注意到目标链表即为将原链表的左半端和反转后的右半端合并后的结果。

这样我们的任务即可划分为三步:

  1. 找到原链表的中点(参考「876. 链表的中间结点 」)。

    • 我们可以使用快慢指针来 $O(N)$ 地找到链表的中间节点。
  2. 将原链表的右半端反转(参考「206. 反转链表 」)。

    • 我们可以使用迭代法实现链表的反转。
  3. 将原链表的两端合并。

    • 因为两链表长度相差不超过 $1$,因此直接合并即可。

代码

[sol2-C++]
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
class Solution {
public:
void reorderList(ListNode* head) {
if (head == nullptr) {
return;
}
ListNode* mid = middleNode(head);
ListNode* l1 = head;
ListNode* l2 = mid->next;
mid->next = nullptr;
l2 = reverseList(l2);
mergeList(l1, l2);
}

ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast->next != nullptr && fast->next->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}

ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr) {
ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}

void mergeList(ListNode* l1, ListNode* l2) {
ListNode* l1_tmp;
ListNode* l2_tmp;
while (l1 != nullptr && l2 != nullptr) {
l1_tmp = l1->next;
l2_tmp = l2->next;

l1->next = l2;
l1 = l1_tmp;

l2->next = l1;
l2 = l2_tmp;
}
}
};
[sol2-Java]
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
class Solution {
public void reorderList(ListNode head) {
if (head == null) {
return;
}
ListNode mid = middleNode(head);
ListNode l1 = head;
ListNode l2 = mid.next;
mid.next = null;
l2 = reverseList(l2);
mergeList(l1, l2);
}

public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}

public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}

public void mergeList(ListNode l1, ListNode l2) {
ListNode l1_tmp;
ListNode l2_tmp;
while (l1 != null && l2 != null) {
l1_tmp = l1.next;
l2_tmp = l2.next;

l1.next = l2;
l1 = l1_tmp;

l2.next = l1;
l2 = l2_tmp;
}
}
}
[sol2-Golang]
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
func middleNode(head *ListNode) *ListNode {
slow, fast := head, head
for fast.Next != nil && fast.Next.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
return slow
}

func reverseList(head *ListNode) *ListNode {
var prev, cur *ListNode = nil, head
for cur != nil {
nextTmp := cur.Next
cur.Next = prev
prev = cur
cur = nextTmp
}
return prev
}

func mergeList(l1, l2 *ListNode) {
var l1Tmp, l2Tmp *ListNode
for l1 != nil && l2 != nil {
l1Tmp = l1.Next
l2Tmp = l2.Next

l1.Next = l2
l1 = l1Tmp

l2.Next = l1
l2 = l2Tmp
}
}

func reorderList(head *ListNode) {
if head == nil {
return
}
mid := middleNode(head)
l1 := head
l2 := mid.Next
mid.Next = nil
l2 = reverseList(l2)
mergeList(l1, l2)
}
[sol2-C]
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
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast->next != NULL && fast->next->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}

struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* prev = NULL;
struct ListNode* curr = head;
while (curr != NULL) {
struct ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}

void mergeList(struct ListNode* l1, struct ListNode* l2) {
struct ListNode* l1_tmp;
struct ListNode* l2_tmp;
while (l1 != NULL && l2 != NULL) {
l1_tmp = l1->next;
l2_tmp = l2->next;

l1->next = l2;
l1 = l1_tmp;

l2->next = l1;
l2 = l2_tmp;
}
}

void reorderList(struct ListNode* head) {
if (head == NULL) {
return;
}
struct ListNode* mid = middleNode(head);
struct ListNode* l1 = head;
struct ListNode* l2 = mid->next;
mid->next = NULL;
l2 = reverseList(l2);
mergeList(l1, l2);
}
[sol2-Python3]
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
class Solution:
def reorderList(self, head: ListNode) -> None:
if not head:
return

mid = self.middleNode(head)
l1 = head
l2 = mid.next
mid.next = None
l2 = self.reverseList(l2)
self.mergeList(l1, l2)

def middleNode(self, head: ListNode) -> ListNode:
slow = fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
return slow

def reverseList(self, head: ListNode) -> ListNode:
prev = None
curr = head
while curr:
nextTemp = curr.next
curr.next = prev
prev = curr
curr = nextTemp
return prev

def mergeList(self, l1: ListNode, l2: ListNode):
while l1 and l2:
l1_tmp = l1.next
l2_tmp = l2.next

l1.next = l2
l1 = l1_tmp

l2.next = l1
l2 = l2_tmp

复杂度分析

  • 时间复杂度:$O(N)$,其中 $N$ 是链表中的节点数。

  • 空间复杂度:$O(1)$。

 Comments
On this page
0143-重排链表