3

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:

  1. cut off the tail of the list after the middle segment
  2. 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
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lionel Foxcroft
  • 1,584
  • 3
  • 9
  • 23
  • 1
    "linked list" --> [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/) – trent Feb 17 '21 at 02:06
  • I came across that tutorial months after I started learning rust, and it was way too difficult for me to follow. Now that it's been more than a year, I'll take another crack at it. Thanks for reminding me it exists. – Lionel Foxcroft Feb 17 '21 at 02:08
  • *a reference to any part of the tail of a linked list will make the Rust compiler refuse to let me modify the head* — that's because, given the head, you could navigate the links and ultimately mutate the tail. Mutable references need to be unique. – Shepmaster Feb 17 '21 at 02:22
  • *to just keep a reference to the beginning (soon-to-be end) of the middle chunk* — only if you know that the reference won't be invalidated. If you took the address of the `Box` and not the data it points to, then your algorithm would be flawed. See also the answer text of [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132/155423) – Shepmaster Feb 17 '21 at 02:26
  • @Shepmaster I know why I would get that error, and I completely agree with it. The naive implementation of what I described is wildly unsafe. The reason I'm asking is because leetcode explicitly told me to do it in one pass, and most languages would let me do that, so it would make sense if there's some sort of rust pattern meant for this exact kind of scenario. Possibly something to do with interior mutability, but I don't have experience with that and I don't see how it would help. I've read the other questions, and mine is about how to do it in one pass, not why my code doesn't work. – Lionel Foxcroft Feb 17 '21 at 02:30
  • *and most languages would let me do that* — most languages would let you commit memory unsafety or require a garbage collector as well, but you aren't asking how to introduce either of those. ;-) – Shepmaster Feb 17 '21 at 02:32
  • *leetcode explicitly told me* — this problem isn't well thought out for Rust, either. You can see this because the signature uses `i32` as an index. What's the concept of index -5? – Shepmaster Feb 17 '21 at 02:36
  • Haha I like to think I'm experienced enough to not just directly ask anymore how to shoot myself in the foot, however tempting it may be. I could be completely off base with whether my question does actually have an answer, but my train of thought was along the lines of that java's gc would deal with it, and if I did it in C, it would be fine because I don't need to allocate or reallocate anything. I know RC types are sort of like a garbage collector in themselves, and unsafe gives you C-like powers, so I was guessing someone has a smart way of doing it – Lionel Foxcroft Feb 17 '21 at 02:37
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/228822/discussion-between-lionel-foxcroft-and-shepmaster). – Lionel Foxcroft Feb 17 '21 at 02:39

0 Answers0