链表题目:奇偶链表

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:奇偶链表

出处:328. 奇偶链表

难度

4 级

题目描述

要求

给你一个链表的头结点 head \texttt{head} head,把所有的奇数下标结点排在前面的组,把所有的偶数下标结点排在后面的组,返回重新排列后的链表。

链表的第一个结点视为奇数结点,第二个结点视为偶数结点,以此类推。

在奇数组和偶数组内部的结点的相对顺序应和输入保持一致。

要求空间复杂度为 O(1) \texttt{O(1)} O(1),时间复杂度为 O(n) \texttt{O(n)} O(n)

示例

示例 1:

链表题目:奇偶链表_第1张图片

输入: head   =   [1,2,3,4,5] \texttt{head = [1,2,3,4,5]} head = [1,2,3,4,5]
输出: [1,3,5,2,4] \texttt{[1,3,5,2,4]} [1,3,5,2,4]

示例 2:

链表题目:奇偶链表_第2张图片

输入: head   =   [2,1,3,5,6,4,7] \texttt{head = [2,1,3,5,6,4,7]} head = [2,1,3,5,6,4,7]
输出: [2,3,6,7,1,5,4] \texttt{[2,3,6,7,1,5,4]} [2,3,6,7,1,5,4]

数据范围

  • 链表中结点数目为 n \texttt{n} n
  • 0 ≤ n ≤ 10 4 \texttt{0} \le \texttt{n} \le \texttt{10}^\texttt{4} 0n104
  • -10 6 ≤ Node.val ≤ 10 6 \texttt{-10}^\texttt{6} \le \texttt{Node.val} \le \texttt{10}^\texttt{6} -106Node.val106

解法

思路和算法

如果链表为空,则直接返回空链表即可。当链表不为空时,链表中的每个结点都是奇数结点或偶数结点,且相邻结点的奇偶性不同,因此可以将原始链表分离成奇数链表和偶数链表,然后将偶数链表拼接在奇数链表之后,即完成了链表的重新排列。

原始链表的头结点 head \textit{head} head 也是奇数链表的头结点和结果链表的头结点, head \textit{head} head 的后一个结点是偶数链表的头结点,即 evenHead = head . next \textit{evenHead} = \textit{head}.\textit{next} evenHead=head.next 是偶数链表的头结点。

维护两个指针 odd \textit{odd} odd even \textit{even} even 分别指向奇数结点和偶数结点,初始时 odd = head \textit{odd} = \textit{head} odd=head even = evenHead \textit{even} = \textit{evenHead} even=evenHead。每一步操作更新 odd . next \textit{odd}.\textit{next} odd.next even . next \textit{even}.\textit{next} even.next 指向的结点,使得 odd . next \textit{odd}.\textit{next} odd.next even . next \textit{even}.\textit{next} even.next 分别指向下一个奇数结点和下一个偶数结点,在更新当前奇偶结点的 next \textit{next} next 的指向之后,将 odd \textit{odd} odd even \textit{even} even 分别向后移动一步,到下一个奇数结点和偶数结点。

具体做法为依次执行以下 4 4 4 步操作:

  1. odd . next \textit{odd}.\textit{next} odd.next 指向 even . next \textit{even}.\textit{next} even.next,更新后的 odd . next \textit{odd}.\textit{next} odd.next 指向下一个奇数结点;
  2. odd : = odd . next \textit{odd} := \textit{odd}.\textit{next} odd:=odd.next,将 odd \textit{odd} odd 移动到下一个奇数结点;
  3. even . next \textit{even}.\textit{next} even.next 指向 odd . next \textit{odd}.\textit{next} odd.next,更新后的 even . next \textit{even}.\textit{next} even.next 指向下一个偶数结点;
  4. even : = even . next \textit{even} := \textit{even}.\textit{next} even:=even.next,将 even \textit{even} even 移动到下一个偶数结点。

上述 4 4 4 步操作完成一个奇数结点和一个偶数结点的分离,并将奇数结点和偶数结点移动到下一个奇数结点和下一个偶数结点。重复上述操作,直到全部结点分离完毕。

全部结点分离完毕时, odd \textit{odd} odd 指向最后一个奇数结点, even \textit{even} even 指向 null \text{null} null 或者最后一个偶数结点,取决于链表长度(结点数)是奇数或者偶数。

全部结点分离完毕之后,由于 odd \textit{odd} odd 指向最后一个奇数结点,因此将 evenHead \textit{evenHead} evenHead 拼接在 odd \textit{odd} odd 之后,即完成了链表的重新排列。结果链表的头结点是 head \textit{head} head

下图为示例 1 的重新排列链表的过程。奇数结点和偶数结点分别在两行,绿色和蓝色分别表示 odd \textit{odd} odd even \textit{even} even 指向的结点。

链表题目:奇偶链表_第3张图片

代码

class Solution {
    public ListNode oddEvenList(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode odd = head, even = head.next, evenHead = head.next;
        while (even != null && even.next != null) {
            odd.next = even.next;
            odd = odd.next;
            even.next = odd.next;
            even = even.next;
        }
        odd.next = evenHead;
        return head;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表一次,对每个结点分离和合并操作都是 O ( 1 ) O(1) O(1) 的时间。

  • 空间复杂度: O ( 1 ) O(1) O(1)

你可能感兴趣的:(数据结构和算法,#,链表,链表)