我刚刚开始学习Rust lang,并尝试在Leetcode上进行一些练习。我正在解决问题Middle of the Linked List。
解决方案只是使用慢速和快速指针。这是我在Rust中的代码:
#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
impl ListNode {
#[inline]
pub fn new(val: i32) -> Self {
ListNode {
next: None,
val
}
}
}
struct Solution;
impl Solution {
pub fn middle_node(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let slow = &head;
let fast = &head;
while fast.is_some() && fast.unwrap().next.is_some() {
slow = &(slow.unwrap().next);
fast = &(fast.unwrap().next.unwrap().next);
}
*slow
}
}
但是,我遇到了很多编译器错误,例如:
--> src/main.rs:22:33
|
22 | while fast.is_some() && fast.unwrap().next.is_some() {
| ^^^^ cannot move out of borrowed content
我了解我违反了借款人检查规则,无法从不可变的ref中删除某些内容,但是我应该如何实现这种两指针实现?
任何建议都会有所帮助,谢谢。
答案 0 :(得分:2)
您说的很对,您的问题是您正试图将某些东西移出借用的对象。首先,让我们看一下您的签名。
pub fn middle_node(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
此函数获取head
的所有权并返回列表(列表的某些子列表)的所有权。无疑这不是您想要的,因为它会使对该列表的任何其他引用无效。在这种情况下,我们想借用该参数并返回另一个引用。
pub fn middle_node(head: &Option<Box<ListNode>>) -> &Option<Box<ListNode>> {
没有所有权易主。无需所有权就易手;呼叫者将首先拥有该列表,而最终将拥有该列表。
现在,您将分配给fast
和slow
,因此它们必须是可变的。您无法将其重新分配给普通的let
。
let mut slow = head;
let mut fast = head;
(我还删除了&head
,因为head
现在已经是引用,所以我们不再需要引用了)
现在,最后,正如您所说,您正试图每次将值从选项中移出,这既不必要又使借阅检查器感到困惑。幸运的是,Option
提供了一种方便的方法来引用内部。 as_ref
取一个Option<T>
并将其变成Option<&T>
,因此我们可以借用内部内容。每次as_ref
之前,我们都需要unwrap
。例如,
while fast.is_some() && fast.as_ref().unwrap().next.is_some() {
(请注意as_ref
)并且在其他所有地方,您unwrap
的可选内容都是相同的。最后,返回的*slow
只是变成了slow
,因为slow
又已经是一个引用了,我们现在要返回一个引用。
可运行的代码:
#[derive(PartialEq, Eq, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
impl ListNode {
#[inline]
pub fn new(val: i32) -> Self {
ListNode {
next: None,
val
}
}
}
struct Solution;
impl Solution {
pub fn middle_node(head: &Option<Box<ListNode>>) -> &Option<Box<ListNode>> {
let mut slow = head;
let mut fast = head;
while fast.is_some() && fast.as_ref().unwrap().next.is_some() {
slow = &(slow.as_ref().unwrap().next);
fast = &(fast.as_ref().unwrap().next.as_ref().unwrap().next);
}
slow
}
}
fn arr_to_list(arr: &[i32]) -> Option<Box<ListNode>> {
let mut head = None;
for n in arr {
let mut new_node = ListNode::new(*n);
new_node.next = head;
head = Some(Box::new(new_node));
}
head
}
fn main() {
let node = arr_to_list(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
let mid = Solution::middle_node(&node);
println!("Middle node is {}", mid.as_ref().unwrap().val)
}