20220924 - 143. Reorder List 重排链表

118 阅读2分钟

You are given the head of a singly linked-list. The list can be represented as:

L0 → L1 → … → Ln-1 → Ln

Reorder the list to be on the following form:

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

You may not modify the values in the list's nodes. Only nodes themselves may be changed.   Example 1:

Input: head = [1,2,3,4]
Output: [1,4,2,3]

Example 2:

Input: head = [1,2,3,4,5]
Output: [1,5,2,4,3]

Constraints:

  • The number of nodes in the list is in the range [1, 5 * 104].
  • 1 <= Node.val <= 1000

Solution

自己想的暴力法:头去接尾

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

void reorderList(struct ListNode* head){
    if (head == NULL || head->next == NULL || head->next->next == NULL) return head;
    struct ListNode *P, *Q, *p, *q;
    P = Q = q = head;
    p = P->next;
    while (Q->next) {
        Q = Q->next;
    }
    while (q->next != Q) {
        q = q->next;
    }
    while (P != Q && P->next != Q) {
        P->next = Q;
        Q->next = p;
        P = p;
        p = P->next;
        Q = q;
        q = P;
        while (q->next != Q) q = q->next;
    }
    Q->next = NULL;
    return head;
}

题解给的方法:寻找链表中点 + 链表逆序 + 合并链表

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

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

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

    • 我们可以使用快慢指针来 O(N)O(N) 地找到链表的中间节点。但这里偶数个结点的话是返回第一个中间结点。
  2. 将原链表的右半端反转(参考「206. 反转链表」)。

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

    • 因为两链表长度相差不超过 1,因此直接合并即可。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode *fast, *slow;
    fast = head->next;
    slow = head;
    while (fast && fast->next) {
        fast = fast->next->next;
        slow = slow->next;
    }
    if (fast == NULL) return slow;
    else return slow;
}

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode *cur, *nxt, *pre;
    pre = NULL;
    cur = head;
    while (cur) {
        nxt = cur->next;
        cur->next = pre;
        pre = cur;
        cur = nxt;
    }
    return pre;
}

struct ListNode* mergeList(struct ListNode* L1, struct ListNode* L2){
    struct ListNode *cur, *nxt;
    cur = L1;
    while (L2) {
        nxt = cur->next;
        cur->next = L2;
        L2 = L2->next;
        cur->next->next = nxt;
        cur = nxt;
    }
    return L1;
}

void reorderList(struct ListNode* head){
    if (head == NULL) return;
    struct ListNode *mid = middleNode(head);
    struct ListNode *L2 = mid->next;
    mid->next = NULL;
    L2 = reverseList(L2);
    mergeList(head, L2);
}

题目链接: 143. 重排链表 - 力扣(LeetCode)