算法修炼之路——【链表】Leetcode 328 奇偶链表

这篇博客详细介绍了如何解决LeetCode中的328题——奇偶链表。作者通过分析问题,提出了用原地算法在O(1)空间复杂度和O(n)时间复杂度下重新排列链表的方法。博客内容包括题目描述、思路分析、解题步骤、解题代码及复杂度分析,并提供了GitHub源码链接。
摘要由CSDN通过智能技术生成

题目描述

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为O(1),时间复杂度应为O(nodes)nodes为节点总数。

示例1:

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

示例2:

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

说明:

  • 应保持奇数节点和偶数节点的相对顺序;
  • 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推;

思路分析

我们通过简单的思考,可以想出通过对链表进行“奇数分区”和“偶数分区”进行节点区分,此时我们不免会想到,奇数分区需要一个指针指向奇数分区尾节点oddTail以便后续节点的插入;同样地, 偶数分区也需要一个指针指向偶数分区尾节点evenTail;同时,我们遍历还需要一个遍历指针p

此时我们对遍历、插入的准备工作进行了简单讨论,这里我们通过代码实现时,会发现我们需要对p遍历时对节点的 “奇偶性”进行判断 ,因为这里是下标的奇偶性,故我们可以通过设置一个布尔常量来进行标识。

再进一步思考,因为链表之被分为两个分区,在代码运行过程中链表一般可被表示为三个区域:a. 偶数分区;b. 奇数分区;c. 待遍历分区。如图1所示:

在这里插入图片描述
图1

这里我们可以看到,在p遍历的时候,会已知保持与指针evenTail的前后关系,则我们这里去掉p指针,则现在我们需要的就是两个分区指针oddTail, evenTail和一个布尔变量进行功能实现。这里我们直接给出解题步骤与解题代码:

解题步骤

  1. 初始化两个分区指针oddTail, evenTail和布尔变量isOddNode
  2. 遍历原始链表,根据isOddNode判断evenTail.next是否插入奇数分区;
  3. evenTail.next == null时停止并返回head.

解题代码

    public static ListNode solution(ListNode head) {
        if (head == null || head.next == null || head.next.next == null) {
            return head;
        }

        /* Step1: Init. pointers */
        ListNode oddTail = head;
        ListNode evenTail = head.next;
        
        boolean isOddNode = true;
        /* Step2: go through the head-list
        and
        split nodes according the odevity(奇偶性) of index
         */
        while(evenTail.next != null){
            ListNode node = evenTail.next;
            
            // oddNode: directly insert after oddTail
            if(isOddNode){
                evenTail.next = evenTail.next.next;
                node.next = oddTail.next;
                oddTail.next = node;
                
                oddTail = node;
                isOddNode = false;
            }else{ // evenNode: just move forward
                evenTail = evenTail.next;
                isOddNode = true;
            }
            
        }
        /* Step3: return head */
        return head;
    }

复杂度分析

时间复杂度:我们对原始链表进行了一次遍历,容易理解时间复杂度为O(N);
空间复杂度:我们这里没有设置辅助容器,只需要两个指针和一个布尔量,故空间复杂度为O(1).

GitHub源码

完整可运行文件请访问GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值