1)反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
在写这道题目的时候, 注意数据借用的问题, Rust在对于链表操作的时候, 使用 BOX 在堆内存上动态申请, 所以效率确实不高, 可以使用 unsafe 来操作原始指针来完成对应操作。
对于使用 Option<Box<ListNode>> 可以使用 while let Some( mut xx) = yyy.take() 来完成解引用
对于下一个的修改 还需要注意一点, 要使用 pre = Some(temp) 来装配起来。
针对这道题 主要是使用了快慢指针的做法来完成。
首先声明两个指针 pre -> null, cur -> head
- 使用 temp 存储 cur.next
- 使用 cur.next = pre
- pre 指向 cur,
- cur 指向 temp
pub fn reverse_list(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
if head.is_none() {
return None;
}
let mut pre: Option<Box<ListNode>> = None;
let mut cur = head;
while let Some(mut nt) = cur.take() {
let mut temp = nt.next.take();
nt.next = pre.take();
pre = Some(nt);
cur = temp;
}
pre
}
2 203. 移除链表元素
给你一个链表的头节点
head和一个整数val,请你删除链表中所有满足Node.val == val的节点,并返回 新的头节点 。
- 最好使用虚拟头结点来完成,(不需要Option,直接Box即可)
- 使用一个虚拟头结点的可变借用(&mut Box)开始遍历
- 遍历时获取该可变借用的下一个结点的所有权(通过Option的take方法),并根据需要获取往后结点的所有权,(实际上就是断开链表)
- 根据题意和需求利用拿到的各个所有权做出判断
- 如果该可变借用的下一个结点不会被丢弃,则恢复所有权(如有多个,需要注意顺序,实际上就是恢复链表),置该可变借用为下一个结点的可变借用(即父结点移动)
- 否则置该可变借用的next属性为需要进行遍历的节点(即父结点的下一个结点移动)(这一步实际上也是在恢复所有权,但不是按原顺序进行)
- 遍历完成后一般题目要求返回头结点,对应的这里就是返回虚拟头结点的下一个节点
pub fn remove_elements(head: Option<Box<ListNode>>, val: i32) -> Option<Box<ListNode>> {
let mut head_v = Box::new(ListNode::new(-1));
head_v.next = head;
let mut p = &mut head_v;
while let Some(mut nt) = p.next.take() {
if { nt.val == val } {
p.next = nt.next;
} else {
p.next = Some(nt);
p = p.next.as_mut().unwrap();
}
}
head_v.next
}
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
这道题 常规使用迭代的方法 来完成
在 c/c++ 等语言中 , 使用 cur, cur ->next , cur -> next -> next 来完成操作, 但是在 rust 中这样的操作十分繁琐, 要不停的完成借用和 包装。
所以在 rust 中本道题 适用于使用 递归完成对应操作,match 是天然的状态机匹配
这里的边界条件 递归的终止条件是链表中没有节点,或者链表中只有一个节点,此时无法进行交换。
需要注意的是 在回归的时候, 需要进行装包
impl Solution {
pub fn swap_pairs(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
head.and_then(|mut n| match n.next {
Some(mut m) => {
n.next = Self::swap_pairs(m.next);
m.next = Some(n);
Some(m)
}
None => Some(n),
})
}
}