对于链表中有零个、一个、两个节点的情况,直接返回即可
对于链表的节点数大于两个的情况,需要讨论,看当前节点是第奇数个节点还是第偶数个节点
class Solution {
public ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return head;
}
int cnt = 1;
ListNode lastNode = head;
while (lastNode.next != null) {
cnt++;
lastNode = lastNode.next;
}
int i = 1;
ListNode p = head;
ListNode pre = head;
while (i <= cnt) {
//第奇数个节点
if ((i & 1) == 1) {
pre = p;
p = p.next;
} else {
//第偶数个节点
pre.next = p.next;
lastNode.next = p;
lastNode = lastNode.next;
lastNode.next = null;
p = pre.next;
}
i++;
}
return head;
}
}
这种方法是一边遍历一边处理
另一种方法,分离节点后合并
如果链表为空,则直接返回链表。
对于每个链表,每个节点是奇数节点或者偶数节点。头节点是奇数节点,头节点的后一个节点是偶数节点,相邻节点的奇偶性不同。因此可以将奇数节点和偶数节点分离成奇数链表和偶数链表,然后将偶数链表连接在奇数链表之后,合并后的链表即为结果链表。
原始链表的头节点head也是奇数链表的头节点以及结果链表的头节点,head的后一个节点是偶数链表的头节点。令evenHead=head.next,则evenHead是偶数链表的头节点。
维护两个指针odd和even分别指向奇数节点和偶数节点,初始时odd=head,even=evenHead。通过迭代的方式将奇数节点和偶数节点分离成两个链表,每一步首先更新奇数节点,然后更新偶数节点。
- 更新奇数节点时,奇数节点的后一个节点需要指向偶数节点的后一个节点,因此odd.next=even.next,然后令odd=odd.next,此时odd变成even的后一个节点
- 更新偶数节点时,偶数节点的后一个节点需要指向奇数节点的后一个节点,因此,令even.next = odd.next,然后令even=even.next,此时,even变成odd的后一个节点
在上述操作完成以后,就完成了对一个奇数节点和一个偶数节点的分离。重复上述操作,直到全部节点分离完毕。全部节点分离完毕的条件是even为空节点或者even.next为空节点,此时odd指向最后一个奇数节点(即奇数链表的最后一个节点)
最后令odd.next=evenHead,将偶数链表连接在奇数链表之后,即完成了奇数链表和偶数链表的合并,结果链表的头节点仍然是head
class Solution {
public ListNode oddEvenList(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return head;
}
ListNode evenHead = head.next;
ListNode odd = head;
ListNode even = evenHead;
//也就是当even或者even.next=null时,退出循环
//因为even=null退出循环,应该是链表有奇数个节点
//因为even.next=null退出循环,应该是链表有偶数个节点
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),其中n是链表的节点数,需要遍历链表中的每个节点,并更新指针
- 空间复杂度:O(1),只需要维护有限的指针