Rust 刷题 链表篇

906 阅读3分钟

1)反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。  

image.png

在写这道题目的时候, 注意数据借用的问题, Rust在对于链表操作的时候, 使用 BOX 在堆内存上动态申请, 所以效率确实不高, 可以使用 unsafe 来操作原始指针来完成对应操作。

对于使用 Option<Box<ListNode>> 可以使用 while let Some( mut xx) = yyy.take() 来完成解引用

对于下一个的修改 还需要注意一点, 要使用 pre = Some(temp) 来装配起来。

针对这道题 主要是使用了快慢指针的做法来完成。

首先声明两个指针 pre -> null, cur -> head

  1. 使用 temp 存储 cur.next
  2. 使用 cur.next = pre
  3. pre 指向 cur,
  4. 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 的节点,并返回 新的头节点 。

image.png

  1. 最好使用虚拟头结点来完成,(不需要Option,直接Box即可)
  2. 使用一个虚拟头结点的可变借用(&mut Box)开始遍历
  3. 遍历时获取该可变借用的下一个结点的所有权(通过Option的take方法),并根据需要获取往后结点的所有权,(实际上就是断开链表)
  4. 根据题意和需求利用拿到的各个所有权做出判断
  5. 如果该可变借用的下一个结点不会被丢弃,则恢复所有权(如有多个,需要注意顺序,实际上就是恢复链表),置该可变借用为下一个结点的可变借用(即父结点移动)
  6. 否则置该可变借用的next属性为需要进行遍历的节点(即父结点的下一个结点移动)(这一步实际上也是在恢复所有权,但不是按原顺序进行)
  7. 遍历完成后一般题目要求返回头结点,对应的这里就是返回虚拟头结点的下一个节点
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. 两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

image.png

这道题 常规使用迭代的方法 来完成

在 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),
        })
    }
}