问题描述
给定一个单链表,将所有奇数位置的节点排在前面,偶数位置的节点排在后面。注意这里的奇偶性指的是节点在链表中的位置索引(从 1 开始),而非节点存储的值。
要求原地算法,空间复杂度 O(1),时间复杂度 O(n)。需保持奇数节点和偶数节点内部的相对顺序不变。
解题思路
要实现 O(1) 的空间复杂度,我们不能创建新的链表节点,只能利用现有的指针进行重连。
我们可以同时维护两条子链表:一条由所有奇数位置的节点组成,另一条由所有偶数位置的节点组成。具体做法是定义两个指针,odd 指向当前奇数链表的尾节点,even 指向当前偶数链表的尾节点。初始时,odd 指向头节点,even 指向第二个节点。
在遍历过程中,让 odd 跳过下一个节点直接连到再下一个(即下一个奇数节点),同理处理 even 指针。每次移动后更新对应的尾节点引用。当遍历结束时,将奇数链表的尾节点 odd.next 指向偶数链表的头节点 evenHead,即可完成重组。
代码实现
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var oddEvenList = function(head) {
if (!head) return null;
let odd = head;
let even = head.next;
let evenHead = even; // 保存偶数链表的头节点,用于最后拼接
// 只要偶数节点及其下一个节点存在,就可以继续向后找奇数节点
while (even && even.next) {
// 奇数节点指向下下个节点(即下一个奇数节点)
odd.next = even.next;
odd = odd.next;
// 偶数节点指向下下个节点(即下一个偶数节点)
even.next = odd.next;
even = even.next;
}
// 将奇数链表的尾部连接到偶数链表的头部
odd.next = evenHead;
head;
};

