NC133 链表的奇偶重排

题目描述

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

1. 使用2个队列

使用两个队列分别记录下链表的奇数节点,偶数节点,再遍历链表,依次出队列装回去,只改变value即可。

/**
 * 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) {
        int i = 1;
        queue<int> odd, even;
        
        ListNode* p = head;
        while (p) {
            if (i&1) odd.push(p->val);
            else even.push(p->val);
            
            i++, p=p->next;
        }
        
        p = head;
        // 奇数在前
        while (!odd.empty()) {
            int val = odd.front();
            odd.pop();
            
            p->val = val;
            p = p->next;
        }
        // 偶数在后
        while (!even.empty()) {
            int val = even.front();
            even.pop();
            
            p->val = val;
            p = p->next;
        }
        return head;
    }
};
  • 时间复杂度:O(n)O(n), 遍历了一次链表,和队列,总长度均为n。
  • 空间复杂度:O(n)O(n), 维护了长度和为n的两个队列。

2. 利用链表操作,一次遍历即可(常数空间的解法)

方法一经历了2次遍历,我们可以优化它。我们定义两个头部节点oddeven, 分别表示“奇链表”和“偶链表”的头结点,每遍历一次,往对应链表尾部插入一个节点,最后“奇链表”的尾部指向“偶链表”的头部即可。

alt

为了实现空间O(1)O(1), 我们只能就地操作节点,那么对于“奇链表”,我们把每个奇数节点都指向next的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 || !head->next) return head;
        
        ListNode* odd = head;
        ListNode* even = head->next;
        
        ListNode* temp = even;
        
        while (odd->next && odd->next->next) {
            // 类似于删除链表节点的操作,把偶数节点删掉
          	// 对应上图,就相当于1号点直接指向了3号点
            odd->next = odd->next->next;
            // 同理,2号点指向了4号点
            even->next = even->next->next;
            
            // 指向下一个节点,就是删除前的下2个节点
          	// 对应上图,就是从1号点跳到3号点
            odd = odd->next;
            even = even->next;
        }
        
        odd->next = temp;
        return head;
    }
};
  • 时间复杂度:O(n)O(n), 遍历了一次链表,总长度为n。
  • 空间复杂度:O(1)O(1),常数个变量。