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→…
你不能改变节点的值,只能改变节点的指针。

原题链接

https://leetcode-cn.com/problems/reorder-list/description/

样例

输入: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;
            }
        }
    }
};
posted @ 2021-12-16 20:12  jsqup  阅读(28)  评论(0编辑  收藏  举报