1. 程式人生 > 其它 >6.重排連結串列

6.重排連結串列

題目描述

給定一個連結串列 L:L0→L1→…→Ln−1→LnL:L0→L1→…→Ln−1→Ln,將它變成 L0→Ln→L1→Ln−1→L2→Ln−2→…L0→Ln→L1→Ln−1→L2→Ln−2→…
你不能改變節點的值,只能改變節點的指標。

樣例

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

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

時間複雜度O(n)

一共需要掃描連結串列3次,一次求總長度,一次將後半段的連結串列反向,一次將兩段連結串列交替插入前半段,所以時間複雜度為O(n)

說明

  1. 將後半段的指標都反向
  2. 用兩個指標分別從1和n開始往中間掃描
  3. 結束條件: left != right

程式碼

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        // 先求出連結串列的長度
        ListNode* link = head;
        int sum = 0;
        while (link) {
            link = link->next;
            sum++;
        }

        if (sum <= 2) {
            return;
        }

        // 找到最後一個結點
        ListNode* r = head;
        int num = sum - 1;
        while (num--) {
            r = r->next;
        }

        int median = sum / 2;
        // 找到中間節點
        ListNode* mid = head;
        while (median--) {
            mid = mid->next;
        }

        ListNode* a = mid;
        ListNode* b = mid->next;
        while (b) {
            ListNode* c = b->next;
            b->next = a;
            a = b;
            b = c;
        }
        mid->next = nullptr;

        // 定義左邊和右邊的遍歷結點
        ListNode* left = head;
        ListNode* right = r;

        // 定義總結點
        ListNode* all = new ListNode(0);
        while (left != right) {
            all->next = left;
            all = all->next;
            left = left->next;

            all->next = right;
            all = all->next;
            if (right->next) {
                right = right->next;
            }
        }
    }
};