LC143-重排链表-reorder-list

2021/11/13 基础链表快慢指针

# 题意

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln
1

请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
1

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

# 样例

样例1:

输入:head = [1,2,3,4]
输出:[1,4,2,3]
1
2

样例2:

输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
1
2

# 思路

这个问题非常有趣。综合了很多单链表的操作。

总体思路是:

  1. 找到链表中间节点,分成前后两部分。LC876-链表的中间节点 (opens new window)
  2. 将后半部分反转。LC206-反转链表 (opens new window)
  3. 合并两部分(交替插入)。

复杂度:

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

# 代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public void reorderList(ListNode head) {
        ListNode middleNode = getMiddleNode(head);
        ListNode lastNode = reverseList(middleNode);
        merge(head, lastNode);
    }

    private void merge(ListNode head1, ListNode head2) {
        ListNode p1 = head1;
        ListNode p2 = head2;
        while (p2.next != null) {
            ListNode next1 = p1.next;
            ListNode next2 = p2.next;
            p1.next = p2;
            p2.next = next1;
            p1 = next1;
            p2 = next2;
        }
    }

    private ListNode getMiddleNode(ListNode head) {
        ListNode p1 = head;
        ListNode p2 = head;
        while (p2 != null && p2.next != null) {
            p1 = p1.next;
            p2 = p2.next.next;
        }
        return p1;
    }

    private ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode prev = null;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }
}
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
Last Updated: 2021/12/7 下午2:23:53