只能说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] 属性,你可以向编译器发出建议,让它在合适的情况下尝试内联展开函数。文章来源:https://www.toymoban.com/news/detail-671445.html
另一个解法,更像是C++或者Java选手的思维文章来源地址https://www.toymoban.com/news/detail-671445.html
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
}
}
到了这里,关于Rust踩雷笔记(5)——刷点链表的题(涉及智能指针Box,持续更新)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!