Rust踩雷笔记(5)——刷点链表的题(涉及智能指针Box,持续更新)

只能说Rust链表题的画风和C++完全不一样,作为新手一时间还不太适应,于是单独为链表、智能指针开一篇,主要记录leetcode相关题型的答案以及注意事项。

🍑关键操作
as_ref()Option<T>&Option<T>或者&mut Option<T>转换为Option<&T>
as_mut()Option<T>&mut Option<T>转换为Option<&mut T>,不能对&Option<T>进行转换
⭐️以及注意&&mut叫做借用是非常形象的,既然是借用他人的物品,就不能转移他人物品的所有权
如果要拿走他人物品的所有权,请使用take()
⚠️l1 = p.next这个操作是希望把节点p的next赋给l1,但实际上如果p是对Box<ListNode>的可变借用,就会报错,因为这个过程会有所有权转移,p既然是借用,它就无权处置“物主”拥有的物品。所以此时用take()l1 = p.next.take()表示通过p这个借用,将所有权“拿走”给l1,并将p.next设置为None总之如果要通过借用来转移所有权,可以使用take()

leetcode 2 两数相加——模式匹配+单链表+Box

⭐️两个注意点
🍉里面有官方提供的单链表的实现,可以参考下;
🍉遍历链表可以用loop+match模式匹配的方式

// 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 {
    pub fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let mut t = (l1, l2, 0, 0);
        let mut result = None;
        let mut tail = &mut result;
        loop {
            t = match t {
                (None, None, _, 0) => break,
                (Some(l1), Some(l2), _, mut carry) => {
                    let temp = l1.val + l2.val + carry;
                    let res_temp = temp % 10;
                    carry = temp / 10;
                    (l1.next, l2.next, res_temp, carry)
                }
                (Some(l), None, _, mut carry) | (None, Some(l), _, mut carry) => {
                    let temp = l.val + carry;
                    let res_temp = temp % 10;
                    carry = temp / 10;
                    (l.next, None, res_temp, carry)
                }
                (None, None, _, carry) => {
                    (None, None, carry, 0)
                }
            };
            *tail = Some(Box::new(ListNode::new(t.2)));
            tail = &mut tail.as_mut().unwrap().next;
        }
        result
    }
}

🍉#[inline] 是什么?
是Rust 中的一个属性,用于提示编译器尝试对函数进行内联展开优化。 内联展开是一种优化技术,可以将函数调用的地方替换为函数体的内容,减少了函数调用的开销,提高代码的执行速度。 通过在函数定义之前使用 #[inline] 属性,你可以向编译器发出建议,让它在合适的情况下尝试内联展开函数。

另一个解法,更像是C++或者Java选手的思维

impl Solution {
    pub fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let (mut l1, mut l2) = (l1, l2);
        let mut head = Box::new(ListNode::new(0));
        let mut p = &mut head;
        let mut carry = 0;
        let mut temp = 0;
        while let (Some(node1), Some(node2)) = (l1.as_ref(), l2.as_ref()) {
            temp = node1.val + node2.val + carry;
            p.next = Some(Box::new(ListNode::new(temp % 10)));
            p = p.next.as_mut().unwrap();
            carry = temp / 10;
            l1 = l1.unwrap().next;
            l2 = l2.unwrap().next;
        }
        while let Some(node) = l1.as_ref() {
            temp = node.val + carry;
            p.next = Some(Box::new(ListNode::new(temp % 10)));
            p = p.next.as_mut().unwrap();
            carry = temp / 10;
            l1 = l1.unwrap().next;
        }
        while let Some(node) = l2.as_ref() {
            temp = node.val + carry;
            p.next = Some(Box::new(ListNode::new(temp % 10)));
            p = p.next.as_mut().unwrap();
            carry = temp / 10;
            l2 = l2.unwrap().next;
        }
        if carry != 0 {
            p.next = Some(Box::new(ListNode::new(carry)));
            p = p.next.as_mut().unwrap();
        }
        head.next
    }
}

⭐️⭐️⭐️leetcode 21 合并有序链表——as_ref()、as_mut()、take()的使用

// 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 {
    // 对于链表而言,下面两个操作非常关键
    // as_ref()将Option<T>、&Option<T>或者&mut Option<T>转换为Option<&T>
    // as_mut()将Option<T>、&mut Option<T>转换为Option<&mut T>,不能对&Option<T>进行转换
    // ⭐️以及注意&和&mut叫做借用是非常形象的,既然是借用他人的物品,就不能转移他人物品的所有权
    // 如果要拿走他人物品的所有权,请使用take()
    
    // 堆上创建头结点
    pub fn merge_two_lists(mut l1: Option<Box<ListNode>>, mut l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        // 对于链表而言,下面两个操作非常关键
        // as_ref()将Option<T>、&Option<T>或者&mut Option<T>转换为Option<&T>
        // as_mut()将Option<T>、&mut Option<T>转换为Option<&mut T>,不能对&Option<T>进行转换
        // ⭐️以及注意&和&mut叫做借用是非常形象的,既然是借用他人的物品,就不能转移他人物品的所有权
        // 如果要拿走他人物品的所有权,请使用take()
        
        // 堆上创建头结点
        let mut head = Box::new(ListNode::new(0));
        let mut p = &mut head;  // 尾节点的可变借用
        while let (Some(node1), Some(node2)) = (l1.as_ref(), l2.as_ref()) {
            if node1.val < node2.val {
                p.next = l1;
                p = p.next.as_mut().unwrap();
                l1 = p.next.take();	// 将p.next拥有的转移给l1,并设置p.next为None
            }
            else {
                p.next = l2;
                p = p.next.as_mut().unwrap();
                l2 = p.next.take();
            }
        }
        if l1.is_some() {
            p.next = l1;
        }
        else {
            p.next = l2;
        }
        head.next
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值