Featured image of post 143.重排链表

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

解法一:翻转链表 + 合并链表 + 查询中间节点

观察后发现可以先找到链表的中间节点 aTail(对于节点数为偶数的链表,取两个中间节点中的第一个),通过中间节点将链表分为链表 a 和链表 b,链表 a 的范围是从原链表的头部到 aTail(包括 aTail),链表 b 的范围为 aTail.Next 到链表末尾。然后翻转链表 b,然后可以合并链表 a 和链表 b。

 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
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reorderList(head *ListNode)  {
    if head == nil || head.Next == nil {
        return
    }
    aTail := middleNode(head)
    b := aTail.Next
    aTail.Next = nil // 断开 a 和 b 的连接
    b = reverseList(b)
    mergeList(head, b)
    return
}

// 取以 head 为头节点的链表的中间节点
func middleNode(head *ListNode) *ListNode{
    if head == nil {
        return head
    }
    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 {
    if head == nil || head.Next == nil {
        return head
    }
    var prev *ListNode
    cur := head
    for cur != nil {
        next := cur.Next// 先记录下一个节点
        cur.Next = prev
        prev = cur
        cur = next// 使 cur 指向下一个节点
    }
    return prev
}

func mergeList(a *ListNode, b* ListNode) *ListNode {
    head := a
    for a != nil && b != nil {
        next := a.Next// 记录 a 要指向的下一个节点
        a.Next = b// 更改 a 的指向
        b = b.Next// 更改 b 的指向
        // a.Next.Next 此时存储的是改变前的 b,这行代码必须在 `b=b.Next` 之后执行
        a.Next.Next = next
        a = next// 使 a 指向链表 a 的下一个节点
    }
    return head
}

拓展:对于节点数为偶数的链表,aTail 能不能取两个中间节点的第二个节点?

总结

  1. 当需要更改某一节点的下一个节点的指向时,先存储这个节点的下一个节点的信息,然后马上更改这个节点的下一个节点。
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计