如何在Rust中反转部分链表?LeetCode问题代码修复求助
修复LeetCode「反转链表II」的Rust实现错误
错误原因分析
- 借用规则冲突:代码中先通过
fake_head.as_mut()创建了可变引用curr,随后又对fake_head执行clone()(不可变借用),Rust不允许同一对象同时存在可变和不可变引用,导致编译错误。 - 所有权移动错误:
curr.next是可变引用背后的Option<Box<ListNode>>,直接将其传递给reverse_list会尝试移动所有权,但Rust不允许从可变引用背后直接移动值。 - 无效的所有权消耗:后续遍历
reversed时多次调用unwrap(),每次调用都会消耗Option的所有权,导致后续无法再访问该值。
修复后的完整代码
// Definition for singly-linked list. // #[derive(PartialEq, Eq, Clone, Debug)] // pub struct ListNode { // pub val: i32, // pub next: Option<Box<ListNode>> // } // // impl ListNode { // #[inline] // fn new(val: i32) -> Self { // ListNode { // next: None, // val // } // } // } impl Solution { // 反转前n个节点,返回(反转后的头, 剩余未反转的链表) fn reverse_n(mut head: Option<Box<ListNode>>, n: usize) -> (Option<Box<ListNode>>, Option<Box<ListNode>>) { let mut prev = None; let mut curr = head; for _ in 0..n { if let Some(mut node) = curr { let next = node.next; node.next = prev; prev = Some(node); curr = next; } } (prev, curr) } pub fn reverse_between(head: Option<Box<ListNode>>, left: i32, right: i32) -> Option<Box<ListNode>> { let mut fake_head = Box::new(ListNode::new(-1)); fake_head.next = head; let mut prev_node = &mut fake_head; // 移动到反转区间的前一个节点 for _ in 0..(left - 1) { prev_node = prev_node.next.as_mut().unwrap(); } // 取出要反转的区间的头节点 let reverse_start = prev_node.next.take(); let n = (right - left + 1) as usize; // 反转前n个节点,得到反转后的头和剩余链表 let (reversed_head, remaining) = Self::reverse_n(reverse_start, n); // 拼接反转后的头到前驱节点后 prev_node.next = reversed_head; // 找到反转后的尾节点,拼接剩余链表 let mut reversed_tail = &mut prev_node.next; for _ in 0..(n - 1) { reversed_tail = &mut reversed_tail.as_mut().unwrap().next; } reversed_tail.as_mut().unwrap().next = remaining; fake_head.next } }
关键修改说明
- 新增
reverse_n函数:专门反转链表的前n个节点,同时返回反转后的头节点和剩余未反转的链表,避免了原代码中反转整个链表的低效问题,也方便后续拼接。 - 调整节点定位逻辑:先单独找到反转区间的前驱节点
prev_node,避免同时持有多个冲突的引用。 - 使用
take()安全转移所有权:通过prev_node.next.take()取出要反转的区间头节点,同时将原位置设为None,解决了所有权移动的问题。 - 安全遍历反转后的链表:通过可变引用遍历找到反转后的尾节点,避免了
unwrap()消耗所有权的问题。
内容的提问来源于stack exchange,提问作者mascai
相关产品推荐
相关产品推荐

