Rust 删除链表的倒数第N个节点 解答和进价解答

首先建议看一下知乎大佬的总结这点非常重要!

借用大佬的总结:

  对于 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 };
  // 获取长度后,两种特殊情况需要排除
  // 长度是1
if 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) } })
原文地址:https://www.cnblogs.com/Addoil/p/13447336.html