I am reversing a segment inside a linked list based on a start and end position. For example, reverse_between([1, 2, 3, 4, 5], 2, 4) would return [1, 4, 3, 2, 5].
I was able to solve it, but I'm not happy with my solution because I have to iterate over the middle segment twice:
- cut off the tail of the list after the middle segment
- reverse the middle segment by adding each element onto the front of the tail
From a language-independent perspective, I know that I should be able to just keep a reference to the beginning (soon-to-be end) of the middle chunk, and then when I'm done reversing, I would use that reference to append the tail and be done in one pass. However, a reference to any part of the tail of a linked list will make the Rust compiler refuse to let me modify the head.
Is it possible to solve this problem in one pass?
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>,
}
fn reverse_between(mut head: Option<Box<ListNode>>, m: i32, n: i32) -> Option<Box<ListNode>> {
    let mut head_ptr = &mut head;
    for _ in 1..m {
        head_ptr = &mut head_ptr.as_mut().unwrap().next;
    }
    let mut middle = head_ptr.take();
    let mut middle_ptr = &mut middle;
    for _ in m..=n {
        middle_ptr = &mut middle_ptr.as_mut().unwrap().next;
    }
    let mut tail = middle_ptr.take();
    while let Some(mut x) = middle {
        middle = x.next.take();
        x.next = tail;
        tail = Some(x);
    }
    std::mem::swap(head_ptr, &mut tail);
    head
}
 
    