首先建议看一下知乎大佬的总结这点非常重要!
借用大佬的总结:
对于 leetcode 的单链表定义,take()
, as_ref()
, as_mut()
是最常用的工具。只要理解所有权和借用检查,Rust 链表并没有那么可怕。
首先要清楚 as_ref() 是不可变引用, as_mut() 可变引用, take() 取出后在原来位置放入None。
总共有三种解法
先给出测试用列
let mut l1 = Box::new(ListNode::new(1)); let mut l2 = Box::new(ListNode::new(2)); let mut l3 = Box::new(ListNode::new(3)); let mut l4 = Box::new(ListNode::new(4)); let l5 = Box::new(ListNode::new(5)); l4.next = Some(l5); l3.next = Some(l4); l2.next = Some(l3); l1.next = Some(l2);
第一种:
先求链表长度,然后找到 len - n 那个Node,进行 Node.next = Node.next.next; 当然Rust的写法肯定不会这么简单。首先要知道所有权的概念,
head可定是不能变动的,因此需要引用去迭代出长度。head.as_mut() 迭代出长度,然后就是上面的思路了。
// 转移所有权,让head可变
let mut head = head;
// 迭代出长度 let len = { let mut i = 0;
// 在这个作用域绑定一个引用 let mut fast = head.as_mut(); while let Some(node) = fast{
// 必须要 as_mut(); fast = node.next.as_mut(); i = i + 1; } i };
// 获取长度后,两种特殊情况需要排除
// 长度是1if len == 1 { return None; }
// 取出整数第一个 if len == n { head = head.unwrap().next }
// 在这个作用域绑定一个引用 let mut fast = head.as_mut(); let mut i = 1;while let Some(node) = fast {
// 正着数需要移除的前一个 if i == len - n { node.next = node.next.as_mut().unwrap().next.take(); } fast = node.next.as_mut(); i = i + 1; } return head;
第二种:
伪快慢指针,在Rust里面出现双指针一个是可变一个是不可变是不可能的,两个可变也是不可能的,两个不可变,无法迭代指针,因此,先clone(),
但是Rust 的leetCode定义的链表,clone是深复制,全部会复制一份。这也是这种方法我会感觉还不如第一种。
这种方法的思想参考腾讯云大佬的解析,对快慢指针讲解的很详细,然后转化为Rust代码;
let mut head = head; let mut fast = head.clone(); let mut slow = head.as_mut(); let mut i = 0; while let Some(node) = fast {if i > n-1 { if let Some(node_s) = slow {if node.next == None { node_s.next = node_s.next.as_mut().unwrap().next.take(); } slow = node_s.next.as_mut() } } fast = node.next; i = i + 1; }if i == n { head = head.unwrap().next }return head;
第三种!!!
递归大法,所有权一直在转移,不是通过可变引用修改数据
首先明白什么是递归,先递过去,然后在回来,建议知乎大佬的解答看一下,思路就是先递到链表结尾,然后开始回归,
最后一个函数结束的时候,返回的是最后的一个结点,前一个去拼接返回的最后一个结点,遇见标志位就不做拼接,跳过这个结点。
大概意思就是回归的时候是在最有一个结点左边拼接数据,遇见标志跳过,然后继续拼接。看代码吧!
pub fn remove_nth_from_end(head: Option<Box<ListNode>>, n: i32) -> Option<Box<ListNode>> { remove_nth_from_end_impl(head, n, & mut 0) } pub fn remove_nth_from_end_impl(head: Option<Box<ListNode>>,n:i32,d: &mut i32) -> Option<Box<ListNode>>{
// 组合算子 head.and_then(|mut x|{ // 把next传入递归函数 let next = remove_nth_from_end_impl(x.next, n, d); *d = *d +1; if *d == n { next } else { x.next =next; Some(x) } })