题目描述

给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。
注意是节点的编号而非节点的数值。

方法一 分解+组合

解题思路

可以新建两个辅助链表头,之后分别连接奇数位节点和偶数位节点,然后再把这两个链表组合起来得到结果。
图片说明

图片说明

代码示例

/**
 * struct ListNode {
 *    int val;
 *    struct ListNode *next;
 *    ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* oddEvenList(ListNode* head) {
        // 边界情况
        if(head == NULL)
            return head;
        // 
        ListNode *odd_head = new ListNode(0), *even_head = new ListNode(0);
        ListNode *p = head, *op = odd_head, *ep = even_head;
        // 确定当前位置是奇数还是偶数
        int pos = 1;
        // 遍历原链表,把奇、偶节点放置在odd_head和even_head后
        while(p != NULL) {
            ListNode *t = p->next;
            // 当前位置为奇数
            if(pos % 2 == 1) {
                // 将该节点添加到op后
                op->next = p;
                op = op->next;
                op->next = NULL;
            }
            // 当前位置为偶数
            else {
                // 将该节点添加到ep后
                ep->next = p;
                ep = ep->next;
                ep->next = NULL;
            }
            // 更新p的位置和计数器pos
            p = t;
            pos++;
        }

        // 将偶数节点拼接到奇数节点之后
        op->next = even_head->next;
        // free掉之前新开的两个节点
        even_head->next = NULL;
        free(even_head);
        odd_head->next = NULL;
        free(odd_head);
        return head;
    }
};

复杂度分析

  • 时间复杂度:需要遍历一遍链表,时间复杂度为
  • 空间复杂度:只需要新建两个辅助节点,故空间复杂度为

方法二 奇偶双指针+定位符

解题思路

方法一需要新建两个辅助节点,可以考虑通过两个指针和一个定位符来代替,减少代码长度。
具体来说,定义奇指针odd和偶指针even以及偶数定位符evenHead。通过迭代的方式将奇数节点和偶数节点分离成两个链表,每一步首先更新奇数节点,然后更新偶数节点。更新方法如图示。
图片说明

图片说明

图片说明

even为空或者even->next为空时,退出循环,合并分离好的链表。
图片说明

代码示例

/**
 * struct ListNode {
 *    int val;
 *    struct ListNode *next;
 *    ListNode(int x) : val(x), next(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @return ListNode类
     */
    ListNode* oddEvenList(ListNode* head) {
        // 边界情况
        if(head == NULL)
            return head;

        ListNode* evenHead = head->next; // 定位符
        ListNode* odd = head; // 奇指针
        ListNode* even = evenHead; // 偶指针
        // 遍历链表
        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;
    }
};

复杂度分析

  • 时间复杂度:需要遍历一遍链表,时间复杂度为
  • 空间复杂度:只需要维护有限个指针,故空间复杂度为