链表题目:奇偶链表

该博客详细介绍了如何实现一个O(n)时间复杂度和O(1)空间复杂度的解决方案,用于重新排列链表,使得奇数下标节点在前,偶数下标节点在后。通过维护两个指针odd和even分别遍历奇数和偶数节点,逐步调整链表结构,最终将两个链表合并。这种方法巧妙地避免了额外的空间使用,实现了高效的链表操作。
摘要由CSDN通过智能技术生成

题目

标题和出处

标题:奇偶链表

出处: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 指向的结点。

在这里插入图片描述

代码

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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值