• 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) } })
  • 相关阅读:
    C# 控件缩写大全+命名规范+示例
    Database Link详解
    DataTable.Compute 方法
    Dotfuscator Professional Edition 4.9.7500.9484 混淆工具破解版+使用教程
    C#中的委托和事件(续)
    Jquery 获取元素内容
    ASP.NET 常用类
    JavaScript动态生成访问方法
    LINQ查询操作符
    HTML乱码问题和header结构
  • 原文地址:https://www.cnblogs.com/Addoil/p/13447336.html
Copyright © 2020-2023  润新知