I didn't read the code, but these kind of competitive problems usually don't need unsafe for the (marginally) extra performance. if you get time out, it's usually you are using an algorithm that is not suitable for the problem.
so you are doing merge sort, right? if I read your code correctly, you split the list by fast-slow-pointer-chasing, which should have quadratic complexity.
try to use a length parameter, which should reduce the splitting to linear complexity, and total complexity of O(n log n). here's a sketch:
EDIT
now I think about it, spitting the list by double pointer chasing is O(nlogn), not quadratic. using an explicit length parameter may (or may not) improve the performance a little bit, but it's the same complexity nevertheless.
so the sketch below probably won't improve the performance much, but I'll leave it unedited anyway.
END OF EDIT
// merge two non-empty sorted list
fn merge(head1: Box<ListNode>, head2: Box<ListNode>) -> Box<ListNode> {
todo!();
}
// split the list of given length into two, if `len` is odd, first list is shorter
// `len` must be >= 2, otherwise panic
fn split(head: Box<ListNode>, len: usize) -> (Box<ListNode>, Box<ListNode>) {
todo!()
}
// recursive merge sort a non-empty list of given length
fn merge_sort(head: Box<ListNode>, len: usize) -> Box<ListNode> {
if len == 1 {
return head;
}
let (head1, head2) = split(head, len);
let head1 = merge_sort(head1, len / 2);
let head2 = merge_sort(head2, len - len / 2);
merge(head1, head2)
}
pub fn sort_list(head: Option<Box<ListNode>>) -> Option<BoxList<Node>> {
head.map(|head| {
let len = todo!();
merge_sort(head, len)
})
}